Russian Qt Forum

Программирование => Общий => Тема начата: Igors от Декабрь 12, 2017, 10:00



Название: Проблемы обобщения
Отправлено: Igors от Декабрь 12, 2017, 10:00
Добрый день

Есть класс CGeometry (полигонный объект). Он управляется таким методом
Код
C++ (Qt)
void CGeometry::SetTransform(
const Coordinate & position,     // позиция объекта
const double angles[3],           // углы поворота
const double scale[3] );           // масштабы по осям
И есть класс камера для которого трансформация задается по-другому
Код
C++ (Qt)
void CCamera::SetTransform(
const Coordinate & position,     // позиция камеры
const Coordinate & reference,   // точка куда камера смотрит
double roll );                          // угол поворота вокруг оси зрения
И вот есть еще один класс CLight (источник света) для которого SetTransform задается точно так же как и для CCamera. Сейчас это решается просто дублированием кода (его не так уж много). Но все-таки интересно - а как грамотно (или правильно)? Очевидное наследование камеры и источника от одного базового класса (напр CReferenceObject) не нравится - слишком уж мало общего у этих классов (ну 5% отсилы) чтобы заряжать общую базу. Тогда какие еще возможности?

Спасибо


Название: Re: Проблемы обобщения
Отправлено: ssoft от Декабрь 12, 2017, 11:48
Здесь возможно несколько вариантов. Вот некоторые из них.

1. Наследование от общего интерфейса Transformable, который в общем случае будет абстрактным, а конкретная реализация  уточняться так называемыми деталями.

+ обобщение всех типов через общие интерфейсы Transformable и любой <Atribute>able.
+ сокрытие (как следствие, легкая замена) и множественность деталей реализации
- множественные наследования, сложность модели, определенный способ мышления (DDD).

2. Похожая реализация

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

3. Выделение отдельной сущности

В примере можно выделить отдельную сущность Transform, которая и будет нести в себе всю функциональность. Соберет разные реализации в одну сущность.
Тогда другие типы будут принимать только готовый экземпляр объекта Transform.



Название: Re: Проблемы обобщения
Отправлено: Racheengel от Декабрь 12, 2017, 13:01
Метод 1 - не сработает, т.к. интерфейсы должны быть разными.
Метод 2 - в принципе, для малой задачи самое оно. Но если вдруг "общее" разрастется - тогда плохо.
Метод 3 - вообще какой-то ад. Будет жуткий микс из кастов и свитчей.

Я бы лично либо использовал метод 2, либо сделал класс вроде CBaseTransform, в котором бы собрал общий функционал для камеры и света, и затем использовал бы его как член классов камеры и источника света.



Название: Re: Проблемы обобщения
Отправлено: ssoft от Декабрь 12, 2017, 16:21
Я бы лично либо использовал метод 2, либо сделал класс вроде CBaseTransform, в котором бы собрал общий функционал для камеры и света, и затем использовал бы его как член классов камеры и источника света.

Это ж и есть методы 2 и 3). Только вместо CBaseTransform был предложен Transform, собирающий общий функционал по работе с трансформациями).


Название: Re: Проблемы обобщения
Отправлено: Igors от Декабрь 13, 2017, 08:21
Да, 3 выглядит самым идейным
Код
C++ (Qt)
class CTransformer {
 ...
 void SetGeometryTransform( const Coordinate & pos, const float angle[3], const float scale[3] );
 void SetReferenceTransform( const Coordinate & pos, const Coordinate & reference, double roll );
 ...
};
Ну и делать его членом CGeometry, CCamera, CLight и др. Тогда метод SetReferenceTransform можно использовать как для CCamera, так и для CLight.

Однако хранить сами данные (напр position, reference и др) этот новый класс вряд ли сможет. Надо делегироваться к объекту членом которого он является - и опять придется разбираться кто там CCamera или CLight.

Кстати общий базовый для всех объектов есть. И явно проще долить ф-ции SetTransform в базовый, плюс что-то типа virtual GetTransformType. Но так явно "god class"

 


Название: Re: Проблемы обобщения
Отправлено: ssoft от Декабрь 13, 2017, 08:34
Кстати общий базовый для всех объектов есть. И явно проще долить ф-ции SetTransform в базовый, плюс что-то типа virtual GetTransformType. Но так явно "god class" 

По хорошему, я бы рекомендовал пересмотреть объектно-ориентированную модель и перейти от наследования к агрегации. Но только если есть желание и время)).
Наличие у разнородных типов общего предка "god class" - это достаточно серьезное ограничение.

На счет "хранить сами данные (напр position, reference и др) этот новый класс вряд ли сможет" могу порекомендовать использовать для CTransformer PIMPL технику. Тогда в зависимости от внутреннего представления CTransformer может хранить совершенно разный набор данных.


Название: Re: Проблемы обобщения
Отправлено: Racheengel от Декабрь 13, 2017, 11:19
Я бы лично либо использовал метод 2, либо сделал класс вроде CBaseTransform, в котором бы собрал общий функционал для камеры и света, и затем использовал бы его как член классов камеры и источника света.

Это ж и есть методы 2 и 3). Только вместо CBaseTransform был предложен Transform, собирающий общий функционал по работе с трансформациями).

Просто Вы написали "Соберет разные реализации в одну сущность" - но по сути то реализация будет одна, для одного случая, а "не для всех возможных", когда без свитчей никак)