DECORATOR模式--《敏捷式軟體開發 (Agile Software Development)》讀書筆記(二)

來源:互聯網
上載者:User

    比如現在我們有如下的幾個類:

class CGShape
{
public:
    ~CGShape();
    virtual void Draw() = 0;
};

class CGRectangle : public CGShape
{
public:
    void Draw();
};

class CGSquare : public CGShape
{
public:
    void Draw();
};

class CGCircle : public CGShape
{
public:
    void Draw();
};

    如果現在有些代碼的使用者有一個特殊的需要,就是要在繪製出圖形的時候同時把圖形的中心點也繪製出來,那我們該怎麼辦呢?
    很顯然,不能直接給各個類的Draw方法中加上繪製中心點的代碼,因為並不是所有的使用者都需要這個功能。
    那麼我們可以給基類CGShape增添一個bool類型的成員變數m_bDrawCenter,並添加一個設定該變數值的公有方法SetDrawCenter,再在各個子類的Draw方法裡面根據變數m_bDrawCenter的值來判斷是否繪製中心點。需要繪製中心點的使用者在調用Draw方法之前先調用SetDrawCenter方法把m_bDrawCenter設定為true。
    還有一個方法,就是分別以類CGRectangle、CGSquare和CGCircle為基類繼承,在各個子類中重載Draw方法,在該方法裡面添加繪製中心點的代碼。
    上面兩種方法都可行,可是我們來仔細分析一下這兩種方法的缺陷:
    方法一,每個類中的Draw方法中都要添加判斷變數m_bDrawCenter的值的代碼和繪製中心點的代碼,這些代碼在每個類中都是重複的,添加的工作也是非常枯燥無味。如果說類很多的話,那麼做這個工作的程式員會崩潰的。最重要的一點是,如果上面那些類都是包含在庫檔案中,沒有原始碼,那麼這個方法就根本行不通。
    方法二,看起來似乎很符合物件導向設計(OOD),也不需要上面那些類的原始碼。但是,這樣會產生大量子類,並增加了類的階層。而且繼承下來的每個子類也都是修改Draw方法,而且添加的繪製中心點的代碼也都是重複的。
    為了避免上面所說的各種缺陷,我們可以使用DECORATOR模式。看下面這個類:

class CGDrawShapeWithCenter : public CGShape
{
public:
    CGDrawShapeWithCenter(CGShape *pShape);
    void Draw();

private:
    CGShape *m_pShape;
};

CGDrawShapeWithCenter::CGDrawShapeWithCenter(CGShape *pShape)
{
    // 得到指向具體圖形的指標
    m_pShape = pShape;
}

void CGDrawShapeWithCenter::Draw()
{
    m_pShape->Draw();
    // 在這裡添加繪製中心點的代碼
}

    這個類使用起來非常簡單,下面這個函數就是繪製一個圓以及圓心:

void DrawCircleWithCenter()
{
    CGCircle circle;
    CGDrawShapeWithCenter shape(&circle);
    shape.Draw();
}

    在類CGDrawShapeWithCenter中,我們通過一個指向CGShape的指標獲得了要繪製的圖形的控制權,使用者在調用Draw方法時並沒有覺得有什麼不同。我們在即不會修改任何類,也不會產生大量子類,更不會有大量重複代碼的情況下,滿足了特殊使用者的需求。
    當然我上面舉的這個例子非常簡單,但是足以說明DECORATOR模式的優點。需要注意的一點就是,類CGDrawShapeWithCenter必須實現所有類CGShape的介面,在不需要修改的介面實現中只要調用指向CGShape的指標m_pShape相應的方法就行了。
    現在,有人也許會問:為什麼類CGDrawShapeWithCenter要從類CGShape繼承?從上面的代碼上來看,單獨寫一個類CGDrawShapeWithCenter也可以實現所有的功能。但是,請看下面這個函數:

void DrawShape(CGShape *pShape)
{
    pShape->Draw();
}

    這個函數是使用者寫來繪製圖形的。如果類CGDrawShapeWithCenter不是從類CGShape繼承,那麼要在繪製圖形的同時把圖形的中心也繪製出來,就必須修改這個函數:

void DrawShape(CGDrawShapeWithCenter *pShape)
{
    pShape->Draw();
}

    而如果類CGDrawShapeWithCenter是從類CGShape繼承來的,使用者就不用修改上面的函數。因為利用類的多態性,把一個類CGDrawShapeWithCenter對象的指標傳給函數就行了。比如下面這樣:

CGCircle circle;
CGDrawShapeWithCenter shape(&circle);
DrawShape(&shape);

    也就是說,所有用CGShape的地方都能用CGDrawShapeWithCenter,從而發揮C++類的多態性的強大功能。在這種情況下,使用者代碼的修改量也可以降到最小。而這樣做最大的好處是decorator類CGDrawShapeWithCenter還能被其他decorator類來修飾。其實,DECORATOR模式最精妙的地方就是decorator類是從要修飾的類的基類繼承,而且有一個指向被修飾類的指標的成員。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.