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