2013-07-12 29 views
0

我創建了ColorBlockImageBlock從抽象Block類繼承的類。 Block實現大小和位置,並有一個抽象方法draw()ColorBlock實現color屬性並將其自身描繪爲一個顏色方塊。 ImageBlock執行image屬性並將其自身繪製爲一個帶有圖像的正方形。具有混合屬性的令人討厭的類層次結構

現在我想讓塊可移動,但我也想保留不可移動的塊。 基本上我將不得不創建MovableColorBlockMovableImageBlock,他們都執行完全相同的移動動作。 類層次結構是這樣的:

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

正如你看到的,我實現兩倍的移動動作。 來實現,這將是類似的另一種方式:

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

現在我實現了移動只有一次,但ColorImage兩次。 有沒有簡單的解決方案,還是我需要重複的代碼?

回答

1

這是幾乎所有圖形/物理引擎都會遇到的問題。

我會推薦讓Movable塊成爲Block的子類,並從中派生出Color和Image塊。畢竟,一個不移動的塊只是一個沒有速度的移動塊。

+0

不是我正在尋找的東西,但tbh這是目前爲止唯一的理智答案:P –

1

你可能想看看Decorator Pattern

爲您的特定情況下,你能想象MovableBlock作爲裝飾,以塊,它可以適用於ColorBlockImageBlock(這將是ConcreteComponents到組件Block)。

下面是一個備用example - 查看ScrollableWindow說明,這可能會使您更容易看到與您的示例類比。

+0

這也是一個可行的解決方案,但很難維護,並且不能真正用於C++的類層次結構。 –

0

您可以讓您的MovableColorBlockMovableImageBlock「MoveableBlock」的朋友類繼承其各自的「不移動」Block類。你仍然有兩個額外的類,但friend聲明將讓他們訪問MoveableBlock

1

另一種選擇是創建一個Movable接口(純虛類)聲明用於移動方法移動實現,並從中獲得實現的子類這些方法:


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

編輯

呀,如果move()方法真的是子類之間是相同的,那麼這是不是你想要的。

聽起來好像move()操作對於draw()操作是正交的,這對我來說建議是聚合而不是子類。所以讓我們稍微左轉一下。

A 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類,不重複代碼。在這種方案下,塊的可移動性是在運行時建立的,而不是編譯時間;這可能會或可能不符合您的目標。

+0

真的不能滿足我,接口幾乎不是一個合適的解決方案,這是其中一個看起來確實錯誤的案例之一。這並不能真正創建適當的層次結構樹,你不能(只要在編程中可以做任何事情,但不應該)只是通過接口實現所有功能。 –

+0

@MarkusMeskanen:見編輯。 –

+0

現在好多了,今天晚些時候我會回家試試。可能仍然不是我正在尋找的東西,但我稍後會想一想。 –