C# 設(shè)計(jì)模式系列教程-組合模式
1. 概述
將對象組合成樹形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu)。組合模式使得用戶對單個(gè)對象和組合對象的使用具有一致性。
2. 解決的問題
當(dāng)希望忽略單個(gè)對象和組合對象的區(qū)別,統(tǒng)一使用組合結(jié)構(gòu)中的所有對象(將這種“統(tǒng)一”性封裝起來)。
3. 組合模式中的角色
3.1 組合部件(Component):它是一個(gè)抽象角色,為要組合的對象提供統(tǒng)一的接口。
3.2 葉子(Leaf):在組合中表示子節(jié)點(diǎn)對象,葉子節(jié)點(diǎn)不能有子節(jié)點(diǎn)。
3.3 合成部件(Composite):定義有枝節(jié)點(diǎn)的行為,用來存儲(chǔ)部件,實(shí)現(xiàn)在Component接口中的有關(guān)操作,如增加(Add)和刪除(Remove)。
4. 模式解讀
4.1 組合模式的類圖
4.2 組合模式的實(shí)現(xiàn)代碼
/// <summary> /// 一個(gè)抽象構(gòu)件,聲明一個(gè)接口用于訪問和管理Component的子部件 /// </summary> public abstract class Component { protected string name; public Component(string name) { this.name = name; } /// <summary> /// 增加一個(gè)節(jié)點(diǎn) /// </summary> /// <param name="component"></param> public abstract void Add(Component component); /// <summary> /// 移除一個(gè)節(jié)點(diǎn) /// </summary> /// <param name="component"></param> public abstract void Remove(Component component); /// <summary> /// 顯示層級結(jié)構(gòu) /// </summary> public abstract void Display(int level); } /// <summary> /// 葉子節(jié)點(diǎn) /// </summary> public class Leaf : Component { public Leaf(string name) : base(name) { } /// <summary> /// 由于葉子節(jié)點(diǎn)沒有子節(jié)點(diǎn),所以Add和Remove方法對它來說沒有意義,但它繼承自Component,這樣做可以消除葉節(jié)點(diǎn)和枝節(jié)點(diǎn)對象在抽象層次的區(qū)別,它們具備完全一致的接口。 /// </summary> /// <param name="component"></param> public override void Add(Component component) { Console.WriteLine("Can not add a component to a leaf."); } /// <summary> /// 實(shí)現(xiàn)它沒有意義,只是提供了一個(gè)一致的調(diào)用接口 /// </summary> /// <param name="component"></param> public override void Remove(Component component) { Console.WriteLine("Can not remove a component to a leaf."); } public override void Display(int level) { Console.WriteLine(new string('-',level) + name); } } /// <summary> /// 定義有枝節(jié)點(diǎn)的行為,用來存儲(chǔ)部件,實(shí)現(xiàn)在Component接口中對子部件有關(guān)的操作 /// </summary> public class Composite : Component { public Composite(string name) : base(name) { } /// <summary> /// 一個(gè)子對象集合,用來存儲(chǔ)其下屬的枝節(jié)點(diǎn)和葉節(jié)點(diǎn) /// </summary> private List<Component> children = new List<Component>(); /// <summary> /// 增加子節(jié)點(diǎn) /// </summary> /// <param name="component"></param> public override void Add(Component component) { children.Add(component); } /// <summary> /// 移除子節(jié)點(diǎn) /// </summary> /// <param name="component"></param> public override void Remove(Component component) { children.Remove(component); } public override void Display(int level) { Console.WriteLine(new string('-', level) + name); // 遍歷其子節(jié)點(diǎn)并顯示 foreach (Component component in children) { component.Display(level+2); } } }
4.3 客戶端代碼
class Program { static void Main(string[] args) { // 生成樹根,并為其增加兩個(gè)葉子節(jié)點(diǎn) Component root = new Composite("Root"); root.Add(new Leaf("Leaf A in Root")); root.Add(new Leaf("Leaf B in Root")); // 為根增加兩個(gè)枝節(jié)點(diǎn) Component branchX = new Composite("Branch X in Root"); Component branchY = new Composite("Branch Y in Root"); root.Add(branchX); root.Add(branchY); // 為BranchX增加頁節(jié)點(diǎn) branchX.Add(new Leaf("Leaf A in Branch X")); // 為BranchX增加枝節(jié)點(diǎn) Component branchZ = new Composite("Branch Z in Branch X"); branchX.Add(branchZ); // 為BranchY增加葉節(jié)點(diǎn) branchY.Add(new Leaf("Leaf in Branch Y")); // 為BranchZ增加葉節(jié)點(diǎn) branchZ.Add(new Leaf("Leaf in Branch Z")); // 顯示樹 root.Display(1); Console.Read(); } }
運(yùn)行結(jié)果
5. 透明方式與安全方式
5.1 透明方式:在Component中聲明所有來管理子對象的方法,其中包括Add,Remove等。這樣實(shí)現(xiàn)Component接口的所有子類都具備了Add和Remove方法。這樣做的好處是葉節(jié)點(diǎn)和枝節(jié)點(diǎn)對于外界沒有區(qū)別,它們具備完全一致的接口。
5.2 安全方式:在Component中不去聲明Add和Remove方法,那么子類的Leaf就不需要實(shí)現(xiàn)它,而是在Composit聲明所有用來管理子類對象的方法。
5.3 兩種方式有缺點(diǎn):對于透明方式,客戶端對葉節(jié)點(diǎn)和枝節(jié)點(diǎn)是一致的,但葉節(jié)點(diǎn)并不具備Add和Remove的功能,因而對它們的實(shí)現(xiàn)是沒有意義的;對于安全方式,葉節(jié)點(diǎn)無需在實(shí)現(xiàn)Add與Remove這樣的方法,但是對于客戶端來說,必須對葉節(jié)點(diǎn)和枝節(jié)點(diǎn)進(jìn)行判定,為客戶端的使用帶來不便。
6. 模式總結(jié)
6.1 優(yōu)點(diǎn)
6.1.1 使客戶端調(diào)用簡單,它可以一致使用組合結(jié)構(gòu)或是其中單個(gè)對象,簡化了客戶端代碼。
6.1.2 容易在組合體內(nèi)增加對象部件??蛻舳瞬槐匾蚣尤肓诵碌牟考拇a。有利于功能的擴(kuò)展。
6.2 缺點(diǎn)
6.2.1 需要抉擇使用透明方式還是安全方式。
6.2.2 透明方式違背了面向?qū)ο蟮膯我宦氊?zé)原則;安全方式增加了客戶需要端判定的負(fù)擔(dān)。
6.3 適用場景
6.3.1 當(dāng)想表達(dá)對象的部分-整體的層次結(jié)構(gòu)時(shí)
6.3.3 希望用戶忽略組合對象與單個(gè)對象的不同,用戶將統(tǒng)一地使用組合結(jié)構(gòu)中的所有對象時(shí)。
上一篇:C#用鏈?zhǔn)椒椒ū磉_(dá)循環(huán)嵌套
欄 目:C#教程
下一篇:C# 設(shè)計(jì)模式系列教程-工廠方法模式
本文標(biāo)題:C# 設(shè)計(jì)模式系列教程-組合模式
本文地址:http://mengdiqiu.com.cn/a1/C_jiaocheng/6485.html
您可能感興趣的文章
- 01-10深入淺出23種設(shè)計(jì)模式
- 01-10TortoiseSVN使用教程
- 01-10C#編程中枚舉類型的使用教程
- 01-10Python設(shè)計(jì)模式編程中的備忘錄模式與對象池模式示例
- 01-10C#中的delegate委托類型基本學(xué)習(xí)教程
- 01-10dotNet中的反射用法入門教程
- 01-10詳解C#的設(shè)計(jì)模式編程之抽象工廠模式的應(yīng)用
- 01-10解析C#設(shè)計(jì)模式編程中的裝飾者模式
- 01-10簡單了解C#設(shè)計(jì)模式編程中的橋接模式
- 01-10C#編程中使用設(shè)計(jì)模式中的原型模式的實(shí)例講解


閱讀排行
本欄相關(guān)
- 01-10C#通過反射獲取當(dāng)前工程中所有窗體并
- 01-10關(guān)于ASP網(wǎng)頁無法打開的解決方案
- 01-10WinForm限制窗體不能移到屏幕外的方法
- 01-10WinForm繪制圓角的方法
- 01-10C#實(shí)現(xiàn)txt定位指定行完整實(shí)例
- 01-10WinForm實(shí)現(xiàn)仿視頻播放器左下角滾動(dòng)新
- 01-10C#停止線程的方法
- 01-10C#實(shí)現(xiàn)清空回收站的方法
- 01-10C#通過重寫Panel改變邊框顏色與寬度的
- 01-10C#實(shí)現(xiàn)讀取注冊表監(jiān)控當(dāng)前操作系統(tǒng)已
隨機(jī)閱讀
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 01-10C#中split用法實(shí)例總結(jié)
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 08-05織夢dedecms什么時(shí)候用欄目交叉功能?
- 04-02jquery與jsp,用jquery
- 01-11ajax實(shí)現(xiàn)頁面的局部加載
- 01-10delphi制作wav文件的方法
- 01-10使用C語言求解撲克牌的順子及n個(gè)骰子