Раздражающая иерархия классов со смешанными атрибутами

Я создал ColorBlock а также ImageBlock подклассы классов из абстрактных Block учебный класс.
Block реализует размер и положение и имеет абстрактный метод draw(),
ColorBlock инвентарь color атрибут и рисует себя в виде цветного квадрата.
ImageBlock инвентарь image атрибут и рисует себя в виде квадрата с изображением внутри него.

Теперь я хочу сделать блоки подвижными, но я также хочу сохранить неподвижные блоки.
В основном я должен был бы создать MovableColorBlock а также MovableImageBlockи они оба выполняют одно и то же движущееся действие.
Иерархия классов будет выглядеть так:

Block
|--ColorBlock
|----MovableColorBlock
|--ImageBlock
|----MovableImageBlock

И, как вы видите, я дважды выполняю движущиеся действия.
Другой способ реализовать это будет что-то вроде:

Block
|--ColorBlock
|--ImageBlock
|--MovableBlock (abstract)
|----MovableColorBlock
|----MovableImageBlock

Сейчас я реализую переезд только один раз, но Color а также Image дважды.
Есть ли простое решение, или мне понадобится дублирующий код?

0

Решение

Это проблема, с которой сталкивается практически каждый графический / физический движок.

Я бы порекомендовал, чтобы блок Movable был подклассом блока, а блок Color и Image был получен из этого. В конце концов, неподвижный блок — это просто движущийся блок без скорости.

1

Другие решения

Вы можете посмотреть на Декоратор Pattern

Для вашего конкретного случая вы могли бы представить MovableBlock в качестве декоратора для блока, который может быть применен к ColorBlock а также ImageBlock (которые будут Конкретными Компонентами к Компоненту Block).

Вот альтернативный пример — посмотри на ScrollableWindow описание, которое может помочь увидеть аналогию с вашим примером.

1

Другой вариант заключается в создании Movable интерфейс (чистый виртуальный класс), который объявляет методы для перемещения и выводит подклассы, которые реализуют эти методы:


Block                 Movable
|                     |
+-ColorBlock----------+-MovableColorBlock
|                     |
+-ImageBlock----------+-MovableImageBlock

редактировать

Да, если move() Метод действительно одинаков между подклассами, тогда это не то, что вы хотите.

Это звучит как move() операция ортогональна draw() операция, которая мне предлагает агрегацию вместо подкласса. Итак, давайте сделаем небольшой левый поворот здесь.

Block имеет позицию; возможно, позиционный параметр может быть подвижным или нет:

class Position
{
public:

Position( int x, int y ) : m_x(x), m_y(y) { }
virtual ~Position() {}

int getX() const { return m_x; }
int getY() const { return m_y; }

virtual bool movable() const { return false; }

protected:

int m_x;
int m_y;
};

class MovablePosition : public Position
{
public:

MovablePosition( int x, int y ) : Position( x, y ) {}
virtual ~MovablePosition() {}

void move( int newX, int newY ) { m_x = newX; m_y = newY; }

virtual bool movable() const { return true; }
};

Тогда ваша база Block класс занимает Position в качестве параметра:

class Block
{
public:

Block( Position *p ) : m_pos( p ) {}
virtual ~Block() {}

virtual void draw() = 0;

Position *getPos() const { return m_pos; }

protected:

Position *m_pos;
};

Тогда, если вы хотите переместить Block экземпляр подкласса, вы бы сначала проверить movable() метод:

if ( myColorBlock.getPos()->movable() )
{
MovablePosition *p = myColorBlock.getPos();
p->move( newX, newY );
myColorBlock.draw();
}

Нет необходимости создавать избыточные MovableXxxBlock классы, без повторения кода. По этой схеме подвижность блока устанавливается во время выполнения, а не во время компиляции; это может или не может быть совместимо с вашими целями.

1

Вы можете сделать свой MovableColorBlock а также MovableImageBlock классы друзей «MoveableBlock» и наследуются от соответствующих им «неподвижных» Block классы. У вас все еще будут два дополнительных класса, но friend декларация позволит им получить доступ к движущейся реализации в MoveableBlock

0
По вопросам рекламы [email protected]