《Head First 設計模式》學習中 裝飾者模式 動態的將責任附加到對象上,若要擴展功能,裝飾者提供了比繼承更有彈性的替代方案 類圖 參與者 1.Component(被裝飾對象的基類) 定義一個對象介面,可以給這些對象動態地添加職責。 2.ConcreteComponent(具體被裝飾對象) 定 ...
《Head First 設計模式》學習中
裝飾者模式
- 動態的將責任附加到對象上,若要擴展功能,裝飾者提供了比繼承更有彈性的替代方案
類圖
參與者
1.Component(被裝飾對象的基類)
定義一個對象介面,可以給這些對象動態地添加職責。
2.ConcreteComponent(具體被裝飾對象)
定義一個對象,可以給這個對象添加一些職責。
3.Decorator(裝飾者抽象類)
維持一個指向Component實例的引用,並定義一個與Component介面一致的介面。
4.ConcreteDecorator(具體裝飾者)
具體的裝飾對象,給內部持有的具體被裝飾對象,增加具體的職責。
涉及角色
- 抽象組件:定義一個抽象介面,來規範準備附加功能的類
- 具體組件:將要被附加功能的類,實現抽象構件角色介面
- 抽象裝飾者:持有對具體構件角色的引用並定義與抽象構件角色一致的介面
- 具體裝飾:實現抽象裝飾者角色,負責對具體構件添加額外功能。
舉例:
經常去一個飯館吃牛肉麵,可以選擇添加雞蛋,火腿,豆皮等配菜,這就可以使用裝飾者模式。
Component(被裝飾對象的基類)
package com.Observer.model; public abstract class food { String size; String description; public String getSize() { return size; } public void setSize(String size) { this.size = size; } public String getDescription() { return description; } public abstract double cost(); }
ConcreteComponent(具體被裝飾對象)
package com.Observer.model; public class BeefNoodles extends food { public BeefNoodles() { description = "牛肉麵小碗"; } @Override public double cost() { if (super.getSize().equals("大碗")) { super.description = "牛肉麵大碗"; return 12.0; } super.description = "牛肉麵小碗"; return 10.0; } }
package com.Observer.model; public class Casserole extends food { public Casserole(){ description = "砂鍋速食麵"; } @Override public double cost() { return 12.0; } }
Decorator(裝飾者抽象類)
package com.Observer.model; public abstract class Condiment extends food { public abstract String getDescription(); }
ConcreteDecorator(具體裝飾者)
package com.Observer.model; public class Ham extends Condiment { food food; public Ham(food food){ this.food = food; } @Override public String getDescription() { return food.getDescription() + ", 火腿"; } @Override public double cost() { return 2.0 + food.cost(); } }
package com.Observer.model; public class Egg extends Condiment { food food; public Egg(food food){ this.food = food; } @Override public String getDescription() { return food.getDescription() + ", 雞蛋"; } @Override public double cost() { return 1.5 + food.cost(); } }
package com.Observer.model; public class Rosa extends Condiment { food food; public Rosa(food food){ this.food = food; } @Override public String getDescription() { return food.getDescription() + ", 豆皮"; } @Override public double cost() { return 1.0 + food.cost(); } }
測試
package com.Observer.model; public class Test { public static void main(String[] args) { food food = new Casserole(); System.out.println(food.getDescription() + " 價格 ," + food.cost() + "元"); food food1 = new BeefNoodles(); food1.setSize("大碗"); food1 = new Ham(food1); food1 = new Ham(food1); food1 = new Egg(food1); food1 = new Rosa(food1); System.out.println(food1.getDescription() + " 價格 ," + food1.cost() + "元"); food food2 = new BeefNoodles(); food2.setSize("小碗"); food2 = new Ham(food2); food2 = new Ham(food2); food2 = new Egg(food2); food2 = new Rosa(food2); System.out.println(food2.getDescription() + " 價格 ," + food2.cost() + "元"); } }
結果
砂鍋速食麵 價格 ,12.0元 牛肉麵小碗, 火腿, 火腿, 雞蛋, 豆皮 價格 ,18.5元 牛肉麵小碗, 火腿, 火腿, 雞蛋, 豆皮 價格 ,16.5元
要點:
- 繼承屬於擴展形式之一,但不見得是達到彈性設計的最佳方案。
- 在我們的設計中,應該允許行為可以被擴展,而不須修改現有的代碼。
- 組合和委托可用於在運行時動態地加上新的行為。
- 除了繼承,裝飾者模式也可以讓我們擴展行為。
- 裝飾者模式意味著一群裝飾者類, 這些類用來包裝具體組件。
- 裝飾者類反映出被裝飾的組件類型(實際上,他們具有相同的類型,都經過介面或繼承實現)。
- 裝飾者可以在被裝飾者的行為前面與/或後面加上自己的行為,甚至將被裝飾者的行為整個取代掉,而達到特定的目的。
- 你可以有無數個裝飾者包裝一個組件。
- 裝飾者一般對組建的客戶是透明的,除非客戶程式依賴於組件的具體類型。
參考博客:https://www.cnblogs.com/chenxing818/p/4705919.html