裝飾模式詳細講解
- 一、定義
- 二、裝飾模式結構
- 核心思想
- 模式角色
- 模式的UML類圖
- 應用場景
- 模式優點
- 模式缺點
- 實例演示
- 圖示
- 代碼演示
- 運行結果
一、定義
裝飾模式(別名:包裝器)
裝飾模式(Decorator Pattern)是結構型的設計模式,它允許在運行時動態地向對象添加新的職責或功能,同時保持對象的原始類不變。通過使用裝飾器模式,可以在不修改現有代碼的基礎上擴展對象的功能,
二、裝飾模式結構
核心思想
1.動態擴展:在不改變原類結構和繼承關系的情況下,動態地為對象添加功能。
2.包裝對象:通過創建一個包裝對象(裝飾器)來包裹真實對象,增加額外功能。
3.接口一致性:裝飾器與真實對象有相同的接口,確保客戶端能以相同的方式與兩者交互。
4.開閉原則:對擴展開放,對修改關閉。新的功能通過添加裝飾器實現,而不是修改原類。
5.靈活組合:允許通過組合多個裝飾器來創建功能更為豐富的對象
模式角色
1.抽象組件(Component):定義一個接口,用于規范準備接收附加責任的對象(即被裝飾對象)。
2.具體組件(ConcreteComponent):實現抽象組件接口,是裝飾器要裝飾的真實對象。
3.裝飾器(Decorator):持有一個抽象組件的引用,并繼承抽象組件的接口。它既可以使用所持有的引用調用被裝飾的組件的方法,也可以增加新的功能。
4.具體裝飾器(ConcreteDecorator):實現裝飾器接口并給具體組件添加職責。它通常包含對具體組件的引用,以及一個或多個用于增加功能的額外方法。
這些角色在裝飾模式中的交互方式是:
- 抽象組件定義了所有裝飾器對象和被裝飾對象需要實現的接口。
- 具體組件實現了抽象組件接口,是準備被裝飾的對象。
- 裝飾器持有一個對抽象組件的引用,并且實現了抽象組件接口。它可以使用這個引用來調用被裝飾對象的方法,并在調用前后添加新的功能。
- 具體裝飾器實現了裝飾器接口,并且給具體組件添加新的職責。它通常包含一個指向被裝飾對象的引用,以及用于實現附加功能的代碼。
模式的UML類圖
應用場景
- 當需要為單個對象提供多種不同的行為或者表現形式時。
- 需要向一個已經存在的類中添加功能,但又不希望修改該類的源代碼或繼承其子類時
- 組合對象:當需要組合多個對象來創建一個具有更多功能的對象時,裝飾模式是一個很好的選擇。通過遞歸組合方式,可以構建出一個具有多種功能的對象。例如,在文件系統中,文件夾可以被視為一個特殊的文件,它可以包含其他文件和文件夾。使用裝飾模式,可以將文件夾裝飾為一個包含額外功能的對象,如支持加密、壓縮等
模式優點
- 動態地給對象添加功能,相比生成子類更加靈活、透明。
- 無需修改原有類就可以擴展功能,符合開閉原則。
- 裝飾器可以被組合,以便在運行時動態地、多次地添加多個職責。
模式缺點
- 這種比繼承更加靈活機動的特性,也同時意味著更加多的復雜性。
- 裝飾模式會導致設計中出現許多小類,如果過度使用,會使程序變得很復雜。
- 不易調試:由于裝飾器模式涉及到多個對象的交互,調試可能會變得相對困難。特別是當裝飾器鏈很長時,追蹤請求和響應的路徑可能會變得復雜。
實例演示
圖示
雞腿堡應用:
代碼演示
package ZhuangShiMoShi;public abstract class Humburger {protected String name;public String getName() {return name;}public abstract double getPrice();}package ZhuangShiMoShi;public class ChickenBurger extends Humburger {public ChickenBurger(){name="雞腿堡";}public double getPrice(){return 10;}}package ZhuangShiMoShi;public abstract class Condiment extends Humburger {protected Humburger humburger;public abstract String getName();}package ZhuangShiMoShi;public class Chilli extends Condiment {public Humburger hum;public Chilli(Humburger hum) {this.hum = hum;}@Overridepublic String getName() {// TODO Auto-generated method stubreturn hum.getName() + " 加辣椒";}@Overridepublic double getPrice() {// TODO Auto-generated method stubreturn hum.getPrice();}}package ZhuangShiMoShi;public class Lettuce extends Condiment {public Humburger hum;public Lettuce(Humburger hum) {this.hum = hum;}@Overridepublic String getName() {// TODO Auto-generated method stubreturn hum.getName()+" 加生菜";}@Overridepublic double getPrice() {// TODO Auto-generated method stubreturn hum.getPrice()+1.5;}}
測試類:
package ZhuangShiMoShi;public class Test {public static void main(String[] args) {Humburger hum = new ChickenBurger();System.out.println(hum.getName() + " 價錢:" + hum.getPrice());Lettuce lettuce=new Lettuce(hum);System.out.println(lettuce.getName()+" 價錢:"+lettuce.getPrice());Chilli chilli1=new Chilli(hum);System.out.println(chilli1.getName()+" 價錢:"+chilli1.getPrice());Chilli chilli2=new Chilli(lettuce);System.out.println(chilli2.getName()+" 價錢:"+chilli2.getPrice());}}
運行結果
該代碼主體是雞腿堡,可以選擇通過添加生菜、醬、辣椒等等許多其他的配料,并根據選擇的配料計算相應的價格。
博主用心寫,讀者點關注;互動傳真情,知識不迷路