2010-10-25 79 views
1

提升從Wikipedia這個例子:如何在不迫使某人重新實現一切的情況下實現裝飾器模式?

// the Window interface 
interface Window { 
    public void draw(); // draws the Window 
    public String getDescription(); // returns a description of the Window 
} 

// implementation of a simple Window without any scrollbars 
class SimpleWindow implements Window { 
    public void draw() { 
     // draw window 
    } 

    public String getDescription() { 
     return "simple window"; 
    } 
} 

// abstract decorator class - note that it implements Window 
abstract class WindowDecorator implements Window { 
    protected Window decoratedWindow; // the Window being decorated 

    public WindowDecorator (Window decoratedWindow) { 
     this.decoratedWindow = decoratedWindow; 
    } 
    public void draw() { 
     decoratedWindow.draw(); 
    } 
} 

我怎麼會,例如,允許用戶實現一個裝飾draw但不getDescription一個裝飾?在我的實際代碼中,有5種可能的裝飾方法。

我看到它的方式,我有3個選項:

  • 把接口上的所有5種方法。缺點是這將迫使他們實施4種方法,只是簡單地稱之爲父母。
  • 創建5個接口,每個方法一個接口。有點笨拙。
  • 根本不要使用接口。失去設計合同。

還有其他的選擇嗎?如果不是,上述哪一項將是最佳選擇?

我正在使用PHP。

回答

1

您可以利用PHP的構造函數繼承並創建一個抽象的默認裝飾器實現AbstractWindowDecorator,它只是獲取裝飾的Window並將所有調用轉發給它。而現在,在實現新的裝飾器時,只需從AbstractWindowDecorator繼承並僅覆蓋所需的這些方法。

// the Window interface 
interface Window 
{ 
    public function draw(); // draws the Window 
    public function getDescription(); // returns a description of the Window 
} 

// implementation of a simple Window without any scrollbars 
class SimpleWindow implements Window 
{ 
    public function draw() 
    { 
     // draw window 
    } 

    public function getDescription() 
    { 
     return "simple window"; 
    } 
} 

// abstract decorator class - note that it implements Window 
abstract class AbstractWindowDecorator implements Window 
{ 
    protected $decoratedWindow; // the Window being decorated 

    public final function __construct ($decoratedWindow) 
    { 
     $this->decoratedWindow = $decoratedWindow; 
    } 

    public function draw() 
    { 
     return $this->decoratedWindow->draw(); 
    } 

    public function getDescription() 
    { 
     return $this->decoratedWindow->getDescription(); 
    } 
} 

// all decorators can now 
class SampleWindowDecorator extends AbstractWindowDecorator 
{ 
    public function draw() 
    { 
     // do something other; 
    } 
} 

AbstractWindowDecorator仍然實現Window,讓你有你的合同權利,你並不需要實現所有方法。而且,沒有抽象類的所有裝飾器創建的「舊方式」也將適用於這種模式。

裝飾的實例就像它在你的例子:(其實,你可以做到這一點,即使沒有構造繼承,但是你需要明確創建的每個裝飾的構造函數)

$w = new SimpleWindow(); 
$d = new SampleWindowDecorator($w); 
echo $d->getDescription(); // "simple window" 

1

如果您使用C++進行開發,則可以使用模板。

而不是從窗口派生WindowDecorator的,你可以從給出的模板參數類派生的,就像這樣:

template <typename T> 
class WindowDecorator : public T 
    { 
    public: 
     // Put here what you want to decorate 
     // Every method not implemented here is simply forwarded to T 
    }; 

WindowDecorator<MyWindow> mywindow; 

當然,這使得一些假設:

  • 的實例你想裝飾應該與裝飾者一起'創造'
  • 你想裝飾的所有類都有一個具有相同參數的構造函數

另一種可能是有一個簡單的「轉發類」,即轉發到裝飾類的所有調用,就像這樣:

class WindowForwarder 
    { 
    public: 
     WindowForwarder (Window &decoratedWindow) : m_decoratedWindow(decoratedWindow) {} 
     virtual void draw() {m_decoratedWindow.draw();} 
     // add all forwarding methods here 
    private: 
     Window &m_decoratedWindow; 
    }; 

然後你就可以有特殊裝飾的子類。只需從WindowForwarder繼承並實現您想要推翻的內容即可。只要WindowForwarder轉發呼叫,所有未被推翻的內容都將轉發到裝飾窗口。

+0

對不起,我應該指定,我正在使用PHP。 – ryeguy 2010-10-25 17:22:17

0

我在你的問題裏面看不到很多裝飾模式。我會看到更多Template Method Pattern

如果需要裝飾的唯一方法是繪製,那麼您需要一個Painter對象 ,然後將不同的邏輯指定到不同的Painters中。

相關問題