2019年2月19日 星期二

設計模式(3) 裝飾者模式(Decorator Pattern)

此篇介紹GoF設計模式(Design Pattern)的其中一種—裝飾者模式(Decorator Pattern)。


適用問題:
  試想我們要為一個咖啡廳設計菜單程式,那我們可能會建立這樣的繼承關係。

  我們有一個飲料介面而底下有許多飲料品項,但通常飲料還能選擇各種佐料,像是牛奶、抹茶等,那這樣我們的品項類別可能會爆炸性的增長 (像是EspressoWithMilkMocha、EspressoWithMilk、EspressoWithMocha之類的),建立單獨類別看來不是個好主意。
  那改成這樣呢?
  但如果我們要加入一個新品項—Tea時就會遇到點問題,我們不會在茶裡加入牛奶,這樣的寫法有著這樣奇怪的點,因此也不太好。

  我們希望的是能再不改變物件自身的基礎上,在執行階段給物件動態的增加一些職責,此就為裝飾者模式。



  裝飾者模式定義:
  "The Decorator Pattern attaches additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality." (裝飾者模式動態地給一個物件加入一些額外的職責,就增加功能來說,裝飾者模式比產生子類別更為靈活)

  裝飾者模式原則:
  1. Classes should be open for extension, but closed for modification.

  裝飾者模式UML:
範例:

code(C++):
class Beverage{
private:
    String description = "Unknown Beverage"
    String getDescription(){
        return description;
    }
public:
    virtual double cost();
}

class CondimentDecortator: public Beverage{
public:
    virtual String getDescription();
}

class Espresso: public Beverage{
public:
    Espresso(){ 
        description = "Espresso";
    }
    duble cost(){ 
        return 1.99;
    }
}

class Milk: public CondimentDecorator{
private:
    Beverage beverage;
public:
    Milk(Beverage beverage){ 
        this.beverage = beverage;
    }
    String getDescription(){
        retrun beverage.getDescription()+", Milk"
    }
    duble cost(){ 
        return .20 + beverage.cost();
    }
}

int main() {
    Beverage* b = new Milk(new Espresso());
    b -> cost();
    return 0;
}




  參考資料:
    1. Head First Design Patterns
    2. JavaScript設計模式與開發實踐 (博碩出版)


沒有留言:

張貼留言