從接觸領域驅動設計的初學階段,到實現一個舊系統改造到DDD模型,再到按DDD規範落地的3個的項目。對於領域驅動模型設計研發,從開始的各種疑惑到吸收各種先進的理念,目前在技術實施這一塊已經基本比較成熟。在既往經驗中總結了一些在開發中遇到的技術問題和解決方案進行分享。 ...
基礎介紹:
動態地給一個對象添加一些額外的職責。適用於需要擴展一個類的功能,或給一個類添加多個變化的情況。
裝飾器,顧名思義就是在原有基礎上添加一些功能。
大家都只知道如果想單純的給原有類增加一些功能,可以直接繼續該類生成一個子類就可以。
舉個例子,如果現在有個手機類,想給手機貼膜,傳統的做法就是新建一個手機類的子類(手機貼膜子類),繼承自手機類。
使用這個子類就可以完成對手機的貼膜操作。
那如果又想給手機按保護殼的話,傳統做法有兩種,可以繼續新建一個手機類的子類(手機保護殼子類),繼承自手機類。
使用這個子類可以給手機按保護殼,但也就失去了給手機貼膜的功能。另一種做法,新建一個手機貼膜類的子類(手機貼膜+保護殼),也就是手機類的子子類。
這樣即可以貼膜也可以按手機殼。
大家思考一個問題,如果有很多個裝飾並且想隨意組合的話,那就有N個子類並且存在很深的繼承鏈路。
想要解決這個問題,就可以用到裝飾器了。
比如貼膜裝飾、保護殼裝飾、貼紙裝飾等等,它們都是獨立存在的,只繼承自裝飾器類。
什麼意思呢?就是說給手機貼膜的時候它並不會給手機按保護殼的功能,職責單一,貼膜裝飾器只負責給手機貼膜。
這樣做有什麼好處呢?好處就是這些裝飾可以隨意組合,比如即想貼膜又想按保護殼,就可以將貼膜裝飾+保護殼裝飾進組組合。
在裝飾器模式中各個角色有:
- 抽象構件(Component)角色:規範手機的構成
- 具體構件(ConcreteComponent)角色:繼承自抽象構件,具體實現手機。(大多情況下,可以省略抽象構件,抽象裝飾類可以直接繼承)
- 抽象裝飾類(Decorator)角色:創建一個構件(Component)對象的實例,可以使用這個實例調用原構件的功能,並規範裝飾類。
- 具體裝飾類(ConcreteDecorator)角色:繼承自抽象裝飾類,具體實現該裝飾功能。
應用場景:
原有類無法修改或者修改困難的情況下,對類進行多次擴展或功能性比較相互獨立,有效防止多次擴展的情況下子類的膨脹。
註:如果類的擴展比較簡單,並且不會多次進行擴展的情況下直接使用類的繼承生成子類的方式更為方便快捷。
創建方式:
為了方便說明,以下實例就不創建抽象構件了。
-
首先先看下不使用裝飾器進行類的擴展
1 /// <summary> 2 /// 手機類 3 /// </summary> 4 public class Phone 5 { 6 public void Print() 7 { 8 Console.WriteLine("手機"); 9 } 10 } 11 12 /// <summary> 13 /// 手機貼膜 14 /// </summary> 15 public class Sticker : Phone 16 { 17 public Sticker() 18 { 19 base.Print(); 20 } 21 22 /// <summary> 23 /// 進行貼膜 24 /// </summary> 25 public void AddSticker() 26 { 27 Console.WriteLine("給手機貼膜"); 28 } 29 } 30 31 /// <summary> 32 /// 手機保護殼 33 /// </summary> 34 public class ProtectiveCase : Phone 35 { 36 public ProtectiveCase() 37 { 38 base.Print(); 39 } 40 41 /// <summary> 42 /// 按保護殼 43 /// </summary> 44 public void AddProtectiveCase() 45 { 46 Console.WriteLine("給手機按保護殼"); 47 } 48 } 49 50 /// <summary> 51 /// 即貼膜又按保護殼 52 /// </summary> 53 public class ProtectiveCaseAndSticker : Sticker 54 { 55 public ProtectiveCaseAndSticker() 56 { 57 } 58 59 /// <summary> 60 /// 按保護殼 61 /// </summary> 62 public void AddProtectiveCase() 63 { 64 Console.WriteLine("給手機按保護殼"); 65 } 66 } 67 68 /// <summary> 69 /// 客戶端 70 /// </summary> 71 class Client 72 { 73 static void Main(string[] args) 74 { 75 //創建一個手機 76 Phone phone = new Phone(); 77 phone.Print(); 78 Console.WriteLine("\r\n"); 79 80 //給手機貼膜 81 Sticker sticker = new Sticker(); 82 sticker.AddSticker(); 83 Console.WriteLine("\r\n"); 84 85 //給手機按保護殼 86 ProtectiveCase protectiveCase = new ProtectiveCase(); 87 protectiveCase.AddProtectiveCase(); 88 Console.WriteLine("\r\n"); 89 90 //即貼膜又按保護殼 91 ProtectiveCaseAndSticker protectiveCaseAndSticker = new ProtectiveCaseAndSticker(); 92 protectiveCaseAndSticker.AddSticker(); 93 protectiveCaseAndSticker.AddProtectiveCase(); 94 Console.ReadKey(); 95 } 96 }
通過上述實例可以看出,如果各個擴展功能比較獨立的話可以直接進行繼承擴展。
如果各個功能直接有交集的情況下,會造成很深的繼承關係。
比如上述實例中,如果單獨貼膜或者單獨安裝保護殼則直接繼承手機類即可。
但如果想要即貼膜又要安裝保護殼,各自繼承手機類的方式就行不通了,只能在貼膜類或者保護殼類的基礎上進行擴展。
如果還有添加手機掛飾,那就還需要再一層繼承關係。
要解決這個問題就用到了裝飾器,下麵看看使用裝飾器是怎麼給手機添加新功能的。
-
使用裝飾器模式對類進行擴展
1 /// <summary> 2 /// 手機類 3 /// </summary> 4 public class Phone 5 { 6 public void Print() 7 { 8 Console.WriteLine("手機"); 9 } 10 } 11 12 /// <summary> 13 /// 裝飾抽象類 14 /// </summary> 15 public abstract class Decorator : Phone 16 { 17 private Phone phone; 18 19 public Decorator(Phone p) 20 { 21 this.phone = p; 22 } 23 24 public abstract void AddDecorator(); 25 } 26 27 /// <summary> 28 /// 貼膜裝飾 29 /// </summary> 30 public class Sticker : Decorator 31 { 32 public Sticker(Phone p) 33 : base(p) 34 { 35 } 36 37 public override void AddDecorator() 38 { 39 Console.WriteLine("給手機貼膜"); 40 } 41 } 42 43 /// <summary> 44 /// 保護殼裝飾 45 /// </summary> 46 public class ProtectiveCase : Decorator 47 { 48 public ProtectiveCase(Phone p) 49 : base(p) 50 { 51 } 52 53 /// <summary> 54 /// 按保護殼 55 /// </summary> 56 public override void AddDecorator() 57 { 58 Console.WriteLine("給手機按保護殼"); 59 } 60 } 61 62 /// <summary> 63 /// 客戶端 64 /// </summary> 65 class Client 66 { 67 static void Main(string[] args) 68 { 69 //單獨給手機貼膜 70 Phone phone = new Phone(); 71 phone.Print(); 72 Decorator sticker = new Sticker(phone); 73 sticker.AddDecorator(); 74 75 //單獨給手機按保護殼 76 phone = new Phone(); 77 phone.Print(); 78 Decorator protectiveCase = new ProtectiveCase(phone); 79 protectiveCase.AddDecorator(); 80 Console.WriteLine("\r\n"); 81 82 //即貼膜又按保護殼 83 phone = new Phone(); 84 phone.Print(); 85 //首先創建貼膜裝飾實例,將手機對象傳入 86 Decorator decorator = new Sticker(phone); 87 //進行貼膜操作 88 decorator.AddDecorator(); 89 //創建保護殼裝飾實例,將貼膜後的手機對象傳入 90 decorator = new ProtectiveCase(decorator); 91 //進行按保護殼操作 92 decorator.AddDecorator(); 93 Console.ReadKey(); 94 } 95 }
從上述實例中可以看出,各個裝飾類只對裝飾抽象類負責,職責單一。
各個裝飾進行組合時,方便隨意。新增裝飾時,只需要新增一個繼承自裝飾抽象類的子類即可實現以原有裝飾的隨意組合使用。
總結:
想要擴展一個類的時候,傳統的繼承生成子類的形式,適用於擴展簡單,並且不會多次擴展的情況下。
而如果一個類的擴展是周期性,多次擴展的或功能性比較相互獨立的情況下,可以使用裝飾器,可以有效的解決傳統繼承擴展子類膨脹的問題。
裝飾模式是繼承的一個替代模式,裝飾模式可以動態擴展一個實現類的功能。
作者:少年真愛 出處:https://www.cnblogs.com/mingnianjiehunba/p/17732216.html 博主的文章沒有高度、深度和廣度,只是湊字數。由於博主的水平不高,不足和錯誤之處在所難免,希望大家能夠批評指出。 博主是利用讀書、參考、引用、抄襲、複製和粘貼等多種方式打造成自己的文章,請原諒博主成為一個無恥的文檔搬運工!