Я создал 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
дважды.
Есть ли простое решение, или мне понадобится дублирующий код?
Это проблема, с которой сталкивается практически каждый графический / физический движок.
Я бы порекомендовал, чтобы блок Movable был подклассом блока, а блок Color и Image был получен из этого. В конце концов, неподвижный блок — это просто движущийся блок без скорости.
Вы можете посмотреть на Декоратор Pattern
Для вашего конкретного случая вы могли бы представить MovableBlock
в качестве декоратора для блока, который может быть применен к ColorBlock
а также ImageBlock
(которые будут Конкретными Компонентами к Компоненту Block
).
Вот альтернативный пример — посмотри на ScrollableWindow
описание, которое может помочь увидеть аналогию с вашим примером.
Другой вариант заключается в создании 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
классы, без повторения кода. По этой схеме подвижность блока устанавливается во время выполнения, а не во время компиляции; это может или не может быть совместимо с вашими целями.
Вы можете сделать свой MovableColorBlock
а также MovableImageBlock
классы друзей «MoveableBlock» и наследуются от соответствующих им «неподвижных» Block
классы. У вас все еще будут два дополнительных класса, но friend
декларация позволит им получить доступ к движущейся реализации в MoveableBlock