2013-10-18 32 views
6

在Decorator設計模式中,我們有一個ItemClass(p.e. Coffee),然後是包含對Coffee的引用的AbstractDecorator(p.e. CoffeeDecorator)以及ConcreteDecorators(例如milk)。我的問題是,爲什麼我們需要AbstractDecorator類,爲什麼不直接從Coffee類繼承Concrete Decorators?或者爲什麼我們沒有包含ItemClass屬性的接口,如果我們已經想確保ConcreteDecorators對ItemClass有引用?使用這個AbstractDecorator,我們只是禁用了一個選項,我們的ConcreteDecorators繼承了其他一些類。提前致謝!Decorator模式中使用抽象Decorator類

回答

1

我們使用抽象類去除具體類中的重複。在裝飾器模式中,您有重複存儲裝飾對象實例並將調用傳遞給它。如果你不會將這個邏輯移動到基礎(抽象)裝飾器,那麼你需要在每個具體的裝飾器中實現這個。


考慮以下飲料接口:

public interface IBeverage 
{ 
    decimal Price { get; } 
    string Description { get; } 
} 

這是由咖啡來實現:

public class Coffee : IBeverage 
{ 
    public decimal Price 
    { 
     get { return 3.5M; } 
    } 

    public string Description 
    { 
     get { return "Coffee"; } 
    } 
} 

現在要創建咖啡第一裝飾。您目前不需要創建抽象裝飾器。讓我們的牛奶蜂免費。只需編寫你需要的最簡單的代碼:

public class Milk : IBeverage 
{ 
    private readonly IBeverage _beverage; 

    public Milk(IBeverage beverage) 
    { 
     _beverage = beverage; 
    } 

    public decimal Price 
    { 
     get { return _beverage.Price; } // price not changed 
    } 

    public string Description 
    { 
     get { return _beverage.Description + " with milk"; } 
    } 
} 

現在你需要另一個裝飾器。讓它成爲奶油:

public class Cream : IBeverage 
{ 
    private readonly IBeverage _beverage; 

    public Cream(IBeverage beverage) 
    { 
     _beverage = beverage; 
    } 

    public decimal Price 
    { 
     get { return _beverage.Price + 2M; } 
    } 

    public string Description 
    { 
     get { return _beverage.Description + " with cream"; } 
    } 
} 

你可以看到重複的代碼。所以,現在是重構的時候了。讓我們繼續重複的代碼,以抽象基裝飾類,它負責將舉辦參照裝飾飲料並通過調用它:

public abstract class BeverageDecorator : IBeverage 
{ 
    private readonly IBeverage _beverage; 

    public BeverageDecorator(IBeverage beverage) 
    { 
     _beverage = beverage; 
    } 

    public virtual decimal Price 
    { 
     get { return _beverage.Price; } 
    } 

    public virtual string Description 
    { 
     get { return _beverage.Description; } 
    } 
} 

現在你可以重寫只有那些行爲由你的裝飾改變了電話。牛奶裝飾將看起來像:

public class Milk : BeverageDecorator 
{ 
    public Milk(IBeverage beverage) 
     : base(beverage) 
    { 
    } 

    public override string Description 
    { 
     get 
     { 
      return base.Description + " with milk"; 
     } 
    } 
} 

更清潔,是嗎?這就是我們使用基礎裝飾器的原因。

+0

好的,我同意。但是,這不是一個小的代價,如果你現在有這樣的奢侈品,那麼你的具體裝飾者可以在需要時實現其他類嗎?我仍然試圖讓這種模式正確,所以我可能錯過了什麼? – Marko

+1

好吧,現在看着你的代碼,我意識到有更多的好處,比設置一個對象的引用來裝飾...這種方式你封裝所有的具體裝飾相同的行爲。但是,我的腦海裏仍然有一種聲音說,如果你可以讓那些具體的裝飾器打開實施,那將是一件好事。:) – Marko

+1

@breakpoint抱歉,沒有得到解決。複製總是邪惡的,所以你需要避免它。您不必強制從抽象裝飾器繼承所有裝飾器。如果其中一個具體的裝飾器應該實現其他類,則從其他類繼承並直接實現IB平衡。順便說一下,這是非常奇怪的要求,從其他一些類繼承。考慮在這種情況下使用組合而不是繼承。 –