设计模式之组合
組合模式介紹
一棵樹結構組合模式是把相似對象或方法組合成一組可被調用的結構樹對象的設計思路。
組合模式不只是可以運用于規則決策樹,還可以做服務包裝將不同的接口進行組合配置,對外提供服務能力,減少開發成本。
組合模式的主要解決的是一系列簡單邏輯節點或者擴展的復雜邏輯節點在不同結構的組織下,對于外部的調用是仍然可以非常簡單的。
組合模式的結構
組件 ?接口描述了樹中簡單項目和復雜項目所共有的操作。
葉節點 是樹的基本結構,它不包含子項目。一般情況下,葉節點最終會完成大部分的實際工作,因為它們無法將工作指派給其他部分。
容器 ? 又名組合,是包含葉節點或其他容器等子項目的單位。容器不知道其子項目所屬的具體類,它只通過通用的接口與其子項目交互。容器接收到請求后會將工作分配給自己的子項目,處理中間結果,然后將最終結果返回客戶端。
客戶端 ?通過組件接口與所有項目交互。因此,客戶端能以相同方式與樹狀結構中的簡單或復雜項目交互。
組合模式的應用場景
當業務是需要實現樹狀對象結構,可以使用組合模式。
組合模式提供兩種共享公共接口的基本元素類型:簡單葉節點和復雜容器。容器中可以包含葉節點和其他容器。這樣就可以構建樹狀嵌套遞歸對象結構。
當希望客戶端代碼以相同方式處理簡單和復雜元素,可以使用組合模式
組合模式中定義的所有元素共用同一個接口。正式由于這接口,客戶端不必在意其所使用的對象的具體類。
組合模式的優缺點
優點:
1、可以利用多態和遞歸機制更方便地使用復雜樹結構
2、開閉原則,無需更改現有代碼,就可以在應用中添加新元素,使其成為對象樹的一部分。
缺點:
1、對于功能差異大的類,提供公共接口或許會有困難。
實現方式
1、確保應用的核心模型能夠以樹狀結構表示,嘗試將其分解為簡單元素和容器。其中容器必須同時包含簡單元素和其他容器。
2、聲明組件接口及其一系列方法,這些方法對簡單和復雜元素都有意義。
3、創建一個葉節點類表示簡單元素,程序中可以有多個不同的葉節點類。
4、創建一個容器類表示復雜元素。在該類中,創建一個數組成員變量來存儲對于其子元素的引用。該數組必須能夠同時保存葉節點和容器,因此請確保將其聲明為組合接口類型。
實現組件接口方法時,記住容器應該將大部分工作交給其子元素來完成。
5、在容器中定義添加和刪除子元素的方法。
這些操作可在組件接口中聲明。會違背“接口隔離原則”,因為葉節點類中的這些方法為空。但是可以讓客戶端無差別地訪問所有元素,即使是組成樹狀結構的元素。
Demo
????///?<summary>///?為簡單對象和復雜對象聲明了通用操作///?</summary>abstract?class?Component{public?Component()?{}///?<summary>///?操作變量///?</summary>///?<returns></returns>public?abstract?string?Operation();public?virtual?void?Add(Component?component)?{throw?new?NotImplementedException();}public?virtual?void?Remove(Component?component)?{throw?new?NotImplementedException();}///?<summary>///?是否是復合///?</summary>///?<returns></returns>public?virtual?bool?IsComposite()?{return?true;}} ????///?<summary>///?葉///?</summary>class?Leaf:Component{public?override?string?Operation(){return?"Leaf";}public?override?bool?IsComposite(){return?false;}} ????///?<summary>///?復合對象(里面既包含葉又包含小復合對象)///?</summary>class?Composite:Component{protected?List<Component>?_children?=?new?List<Component>();public?override?void?Add(Component?component){this._children.Add(component);}public?override?void?Remove(Component?component){this._children.Remove(component);}public?override?string?Operation(){int?i?=?0;string?result?=?"包含的分支都有那些:";foreach?(var?component?in?_children){result?+=?component.Operation();if(i!=_children.Count-1){result?+=?"+";}i++;}return?result?+?")";}} ????///?<summary>///?客戶端///?</summary>class?Client{///?<summary>///?組件調用接口???葉子調用///?</summary>///?<param?name="leaf"></param>public?void?ClientCode(Component?leaf)?{Console.WriteLine("Result:"+leaf.Operation());}///?<summary>///?在基組件類中,客戶端可以與任何組件,簡單和復雜的對象交互,不依賴具體的類///?</summary>///?<param?name="c1"></param>///?<param?name="c2"></param>public?void?ClientCode2(Component?c1,Component?c2){if?(c1.IsComposite()){c1.Add(c2);}Console.WriteLine("Result:"+c1.Operation());}} ????class?Program{static?void?Main(string[]?args){Client?client?=?new?Client();Leaf?leaf?=?new?Leaf();Console.WriteLine("調用葉子......");client.ClientCode(leaf);Console.WriteLine("---------------");Composite?tree?=?new?Composite();Composite?branch1?=?new?Composite();branch1.Add(new?Leaf());branch1.Add(new?Leaf());Composite?branch2?=?new?Composite();branch2.Add(new?Leaf());tree.Add(branch1);tree.Add(branch2);Console.WriteLine("調用復雜對象......");client.ClientCode(tree);Console.WriteLine("---");client.ClientCode2(tree,leaf);Console.ReadKey();}} 計算結果顯示從計算結果可以看出,當第一次只調用葉子時,結果就只顯示葉子,也就是簡單元素,當第二次聲明實例化復雜容器(包含葉子和別的容器)時,輸出結果也可以把所有聲明實例的容器中的所有葉子和子容器都輸出顯示。
其實對于我們業務來說,需要把握好業務的邏輯看到底需要并適合那種模式,這樣才能不為了模式而模式代碼。
小寄語
人生短暫,我不想去追求自己看不見的,我只想抓住我能看的見的。
我是阿輝,感謝您的閱讀,如果對你有幫助,麻煩點贊、轉發 ?謝謝。
總結
- 上一篇: GitHub 的 Action 接入 S
- 下一篇: 基于 gRPC 和 .NET Core