Шаблон проектирования для обработки групп объектов

У меня есть класс item. Каждый экземпляр этого класса представляет собой объект в трехмерном пространстве, может иметь базовые формы, такие как цилиндр, сфера и конус. У class Item есть удобный API для геометрии (радиус, верхний радиус, радиус бота, длина) и трансформаций (поворот, перемещение, масштабирование).

enum ItemType {
    Sphere = 1,
    Cone
}

class Item
{
// ...
public:
    ItemType type();
    void setType(const ItemType &t);

    float radius();
    float length();
    float topRadius();
    float botRadious();
    QMatrix4x4 transformations();

    void setRadius(const float &r);
    void setLength(const float &l);
    void setTopRadius(const float &tr);
    void setBotRadius(const float &br);
    void setTransformations(const QMatrix4x4 &matrix);
// ...
}

Класс экземпляров как 3D-объектов

Часто мне нужно склеить несколько объектов вместе, чтобы сформировать единую форму. Например, ниже соединены две сферы и конус. Геометрия и преобразования объединенного объекта зависят от двух сфер и одного конуса.

Три объекта Три объединенных объекта

Проблема в:

  1. Удобное обращение с единым объектом невозможно
  2. Под обращением я подразумеваю, например, трансформацию. Например, изменение длины единого объекта требует, соответственно, изменения длины среднего конуса и расположения двух сфер.
  3. class Item есть API для удобной работы с каждым отдельным объектом, а не с единым
  4. Для обработки единого объекта мне приходится работать с тремя разными объектами, что мучительно.

Вопрос в том:

Какие шаблоны проектирования лучше всего подходят для удобной обработки унифицированных объектов?


person user3405291    schedule 17.10.2019    source источник
comment
В то время как преобразование может быть применено к любой форме. геометрия зависит от типа объекта: radius не имеет смысла для ограничивающей рамки или TopRadius для сферы...   -  person Jarod42    schedule 17.10.2019
comment
Начните с определения класса Group, который определяет произвольную контрольную точку (скажем, центр масс) и запоминает, как каждый Item в группе позиционируется и поворачивается относительно этой контрольной точки. Это уже позволяет вращать, масштабировать и перемещать группу. Если вам нужно дополнительное поведение (например, растяжение конуса вдоль одной оси), вам нужно будет назначить один из элементов корневым и определить, как каждое изменение влияет на остальную часть группы.   -  person Botje    schedule 17.10.2019
comment
@Botje Какая связь между классом Group и классом Item?   -  person user3405291    schedule 17.10.2019
comment
Group будет содержать набор (std::vector, std::list, ...) из Item экземпляров, каждый из которых имеет перемещение, поворот и масштаб относительно контрольной точки группы.   -  person Botje    schedule 17.10.2019
comment
@Botje Спасибо. Попробую реализовать.   -  person user3405291    schedule 17.10.2019


Ответы (2)


Примечание. Этот вопрос касается объектно-ориентированного проектирования программного обеспечения и шаблонов программного обеспечения, он не имеет ничего общего с C++. Единственная часть, специфичная для C++, — это использование ключевого слова virtual, но даже это — всего лишь ключевое слово, специфичное для C++, которое дает вам полиморфизм, который опять-таки является объектно-ориентированным принципом, а не чем-то уникальным для C++.

Итак, что вам в первую очередь нужно сделать, так это извлечь настоящий интерфейс для того, что вы называете «API». Я бы назвал это Primitive3D, и это был бы class, не содержащий ничего, кроме чисто виртуальных методов. (В С++ это будет virtual function(parameters) = 0.)

Затем каждый из ваших примитивов будет реализовывать интерфейс, предоставляя реализацию для каждого чисто виртуального метода. Если у вас есть какая-то базовая функциональность, которую будут использовать все реализации, то в дополнение к реализации этого интерфейса вы также можете сохранить общий базовый класс. Тем не менее, введение интерфейса сделает ваши возможности более открытыми.

Затем введите новый примитив, возможно, с именем Conglomerate. Опять же, это будет еще один класс, реализующий Primitive3D. Этот класс будет предоставлять свои собственные реализации для установки различных атрибутов, таких как длина и преобразование, и эти реализации будут работать, устанавливая некоторые атрибуты содержащихся примитивов.

Класс Conglomerate также предоставляет несколько специфичных для него функций, которых нет в интерфейсе Primitive3D. Вы должны использовать эти функции для настройки конгломерата, по крайней мере, для заполнения конгломерата его содержимым.

Функция, добавляющая новый член-примитив в конгломерат, может принимать дополнительные параметры, точно указывающие, в какой позиции конгломерата должен появиться новый член, какое преобразование выполнять при масштабировании примитива, какое преобразование выполнять при перемещении примитив и др.

Внутри конгломерат, вероятно, будет использовать vector, содержащий экземпляры некоторой внутренней member структуры, которая будет содержать ссылку на Primitive3D и любую другую информацию, необходимую для того, чтобы знать, как обращаться с этим примитивом. Не делайте ошибку, добавляя эту информацию к самому Primitive3D, она там не принадлежит, потому что примитив не знает и не должен знать, что он является членом конгломерата. Я бы даже сказал, что местоположение примитива не является характеристикой самого примитива; это характеристика пространства, содержащего примитивное, независимо от того, является ли это пространство вселенной или конгломератом.

person Mike Nakis    schedule 17.10.2019
comment
Проголосовали за. Спасибо :) Позвольте мне реализовать этот подход. - person user3405291; 17.10.2019

Глядя на вашу структуру, составной шаблон - это шаблон, который вы должны учитывать. Также идентификация конкретной формы с атрибутом «тип» противоречит объектно-ориентированному дизайну. Он убивает полиморфизм, отличный уникальный инструмент, доступный в ООП. Составной шаблон позволит вам обращаться к элементам, а также к их объединению в одну иерархию.

person Kedar Tokekar    schedule 18.10.2019