设计模式之装饰器
裝飾器模式介紹
俄羅斯套娃裝飾器的核心就是在不改原有類的基礎上給類新增功能。可以避免繼承導致的子類過多,可避免AOP帶來的復雜性。
裝飾器主要解決的是直接繼承下因功能的不斷橫向擴展導致子類膨脹的問題,而是用裝飾器模式后就會比直接繼承顯得更加靈活同時這樣也就不再需要考慮子類的維護。
在實現的過程中,具體實現只關心擴展部分的功能,同時不會影響原有類的核心服務,也不會因為使用繼承方式而導致的多余子類,增加了整體的靈活性。
裝飾器模式滿足單一職責原則,可以在自己的裝飾類中完成功能邏輯的擴展,而不影響主類,同時可以按需在運行時添加和刪除這部分邏輯。另外裝飾器模式與繼承父類重寫方法,在某些時候需要按需選擇,并不一定某一個就是最好。
裝飾器實現的重點是對抽象類繼承接口方法的使用,同時設定被繼承的接口可以通過構造函數傳遞其實現類,由此增加擴展性并重寫方法里可以實現此部分父類實現的功能。
封裝器是一個能與其他目標對象連接的對象。封裝器包含與目標對象相同的一系列方法,它會將所有接收到的請求委派給目標對象,但是封裝器可以在將請求委派給目標前后對其進行處理,所以可能會改變最終結果。
裝飾模式由于目標對象和裝飾器遵循同一接口,因此你可用裝飾來對對象進行無限次的封裝,結果對象將獲得所有封裝器疊加而來的行為。
裝飾器模式的抽象點
抽象構件角色-定義抽象接口
具體構件角色-實現抽象接口,可以是一組
裝飾角色-定義抽象類并繼承接口中的方法,保證一致性
具體裝飾角色-擴展裝飾具體的實現邏輯
繼承可能引發的幾個嚴重問題:
1、繼承是靜態的。你無法在運行時更改已有對象的行為,只能使用由不同子類創建的對象來替代當前的整個對象。
2、子類只能有一個父類。大部分編程語言不支持多繼承。
裝飾器結構
部件 ?聲明封裝器和被封裝對象的公用接口。
具體部件 ?類是被封裝對象所屬的類,它定義了基礎行為,但裝飾類可以改變這些行為。
基礎裝飾 ?類擁有一個指向被封裝對象的引用成員變量。該變量的類型應當被聲明為通用部件接口,這樣它就可以引用具體的部件和裝飾。裝飾基類會將所有操作委派給被封裝的對象。
具體裝飾類 ?定義了可動態添加到部件的額外行為。具體裝飾類會重寫裝飾基類的方法,并在調用父類方法之前或之后進行額外的行為。
客戶端 ?可以使用多層裝飾來封裝部件,只要它能使用通用接口與所有對象交互即可。
適用場景
1、在無需修改代碼的情況下即可使用對象,且希望在運行時為對象新增額外的行為,可以使用裝飾模式。
裝飾能將業務邏輯組織為層次結構,你可為各層創建一個裝飾,在運行時將各種不同邏輯組成對象,由于這些對象都遵循通用接口,客戶端代碼能以相同的方式使用這些對象。
2、當某些業務無法使用繼承來擴展對象行為時,可以使用裝飾模式。
裝飾器模式優缺點
優點:
你需要創建新子類即可擴展對象的行為。
可在運行時添加或刪除對象的功能。
可以用多個裝飾封裝對象來組合幾種行為。
滿足單一職責原則。
缺點:
在封裝器棧中刪除特定封裝器比較困難
實現行為不受裝飾棧順序影響的裝飾比較困難
剛開始各層的初始化配置代碼比較糟糕
Demo
????///?<summary>///?組件///?</summary>public?abstract?class?Component{public?abstract?string?Operation();} } ????///?<summary>///?抽象的裝飾者///?</summary>class?ConcreteComponent:Component{public?override?string?Operation(){return?"ConcreteComponent";}} ????abstract?class?Decorator:Component{protected?Component?_component;public?Decorator(Component?component){this._component?=?component;}public?void?SetComponent(Component?component)?{this._component?=?component;}public?override?string?Operation(){if?(this._component!=null){return?this._component.Operation();}else{return?string.Empty;}}} ????class?ConcreteDecoratorA?:?Decorator{public?ConcreteDecoratorA(Component?comp):base(comp){}public?override?string?Operation(){return?"ConcreteDecoratorA?"?+?base.Operation();}}class?ConcreteDecoratorB:Decorator{public?ConcreteDecoratorB(Component?comp):?base(comp){}public?override?string?Operation(){return?"ConcreteDecoratorA?"?+?base.Operation();}}???? ????public?class?Client{public?void?ClientCode(Component?component)?{Console.WriteLine("Result:"+component.Operation());}} ????class?Program{static?void?Main(string[]?args){Client?client?=?new?Client();var?temp?=?new?ConcreteComponent();Console.WriteLine("Start------");Console.WriteLine();ConcreteDecoratorA?d1?=?new?ConcreteDecoratorA(temp);ConcreteDecoratorB?d2?=?new?ConcreteDecoratorB(d1);Console.WriteLine("Start?Music");client.ClientCode(d2);Console.ReadKey();}} 計算結果其實可以看出裝飾器模式和組合模式還是有異曲同工之處的,裝飾器模式是對既有類中方法的可重寫,也就是可以改變其方法的結構,而組合則是不能改變其既有類中的方法,只能將其組合成想要實現的樣子。
小寄語
人生短暫,我不想去追求自己看不見的,我只想抓住我能看的見的。
我是阿輝,感謝您的閱讀,如果對你有幫助,麻煩點贊、轉發 ?謝謝。
總結
- 上一篇: WPF中一个通用的BoolToXXX转换
- 下一篇: asp.net ajax控件工具集 Au