恼人的类层次结构,具有混合属性

时间:2013-07-12 14:55:02

标签: c++ class inheritance class-hierarchy

我已经从抽象ColorBlock类创建了ImageBlockBlock类子类。 Block实现了大小和位置,并有一个抽象方法draw()ColorBlock实现color属性并将其自身绘制为颜色方块。 ImageBlock实现image属性并将其自身绘制为一个正方形,其中包含图像。

现在我想让块可以移动,但我也想保留不可移动的块。 基本上我必须创建MovableColorBlockMovableImageBlock,并且它们都实现完全相同的移动动作。 类层次结构如下:

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

如你所见,我正在实施两次移动动作。 实现这一点的另一种方法是:

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

现在我只实施移动一次,但ColorImage两次。 有一个简单的解决方案,还是我需要重复的代码?

4 个答案:

答案 0 :(得分:1)

您可能需要查看Decorator Pattern

对于您的特定情况,您可以将MovableBlock想象为要阻止的装饰器,这可以应用于ColorBlockImageBlock(对于组件{{1}将是ConcreteComponents })。

以下是备用example - 请查看Block说明,这可能会让您更容易看到与您的示例类比。

答案 1 :(得分:1)

这是一个几乎每个图形/物理引擎都会遇到的问题。

我建议让Movable块成为Block的子类,并从中获得Color和Image块。毕竟,一个不动的块只是一个没有速度的移动块。

答案 2 :(得分: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类,也不需要重复代码。在这种方案下,块的可移动性在运行时建立,而不是编译时;可能与您的目标相符也可能不兼容。

答案 3 :(得分:0)

您可以将MovableColorBlockMovableImageBlock朋友类设为'MoveableBlock'并继承其各自的“非移动”Block类。您仍然会有两个额外的类,但friend声明将允许他们访问MoveableBlock中的移动实现