一、定義
組合模式:將對象組合成樹形結構以表示“部分-整體”的層次結構。組合模式使得用戶對單個對象和組合對象的使用具有一致性。
解釋:簡單來說,編寫一個類,該類能作用于整體,并且編寫整體中的部分時也能使用該類,而不用做大的更改。
二、UML類圖及基本代碼

基本代碼:
abstract class Component { PRotected string name; public Component(string name) { this.name = name; } public abstract void Add(Component component); public abstract void Remove(Component component); public abstract void Display(int depth); } class Leaf : Component { public Leaf(string name) : base(name) { } public override void Add(Component component) { Console.WriteLine("cannot add to a leaf"); } public override void Remove(Component component) { Console.WriteLine("cannot remove to a leaf"); } public override void Display(int depth) { Console.WriteLine(new string('-', depth) + name); } } class Composite : Component { private IList<Component> children = new List<Component>(); public Composite(string name) : base(name) { } public override void Add(Component component) { children.Add(component); } public override void Remove(Component component) { children.Remove(component); } public override void Display(int depth) { Console.WriteLine(new string('-', depth) + name); foreach (Component component in children) { component.Display(depth + 2); } } }
客戶端進行調用:

Composite root = new Composite("root"); root.Add(new Leaf("leaf A")); root.Add(new Leaf("leaf B")); Composite composite = new Composite("Composite X"); composite.Add(new Leaf("leaf XA")); composite.Add(new Leaf("leaf XB")); root.Add(composite); Composite composite2 = new Composite("Composite XY"); composite2.Add(new Leaf("leaf XYA")); composite2.Add(new Leaf("leaf XYB")); composite.Add(composite2); root.Add(new Leaf("leaf C")); Leaf leaf = new Leaf("Leaf D"); root.Add(leaf); root.Remove(leaf); root.Display(1);
結果如圖:

三、透明方式和安全方式
基本代碼中,leaf類也有add和remove方法,也就是說Component聲明所有用來管理子對象的方法,實現了所有子類都具備其方法的目的。這樣做的好處就是葉節點和枝節點對于外界沒有區別,它們具備完全一致的行為接口。但因為leaf不具備add和remove的功能,所以實現它是沒有意義的。這種方式就是透明方式。
安全方式是葉節點和枝節點不具有相同的接口,由于不夠透明,那么客戶端調用時需要做相應的判斷,帶來了不便。所以在實際項目中使用安全方式和透明方式就需要視情況而定。
四、舉例說明:
繪制一個圖形,該圖形由一個復雜圖形和兩條線段組成。可以自由的移除該圖形。
public abstract class Graphics { public string Name { get; set; } public Graphics(string name) { this.Name = name; } public abstract void Draw(); public abstract void Add(Graphics graphics); public abstract void Remove(Graphics graphics); } public class Line : Graphics { public Line(string name) : base(name) { } public override void Draw() { Console.WriteLine("畫 " + Name); } public override void Add(Graphics graphics) { throw new Exception("不能向簡單圖形line添加圖形"); } public override void Remove(Graphics graphics) { throw new Exception("不能向簡單圖形line移除圖形"); } } public class Circle : Graphics { public Circle(string name) : base(name) { } public override void Draw() { Console.WriteLine("畫 " + Name); } public override void Add(Graphics g) { throw new Exception("不能向簡單圖形Circle添加其他圖形"); } public override void Remove(Graphics g) { throw new Exception("不能向簡單圖形Circle移除其他圖形"); } } public class ComplexGraphics : Graphics { private IList<Graphics> complexGraphicsList = new List<Graphics>(); public ComplexGraphics(string name) : base(name) { } public override void Draw() { foreach (Graphics g in complexGraphicsList) { g.Draw(); } } public override void Add(Graphics graphics) { complexGraphicsList.Add(graphics); } public override void Remove(Graphics graphics) { complexGraphicsList.Remove(graphics); } }
客戶端調用:

ComplexGraphics complexGraphics = new ComplexGraphics("一個復雜圖形和兩條線段組成的復雜圖形"); complexGraphics.Add(new Line("線段A")); ComplexGraphics complexGraphics2 = new ComplexGraphics("一個圓和一條線組成的復雜圖形"); complexGraphics2.Add(new Circle("圓")); complexGraphics2.Add(new Line("線段B")); complexGraphics.Add(complexGraphics2); Line line = new Line("線段C"); complexGraphics.Add(line); Console.WriteLine("復雜圖形的繪制如下:"); Console.WriteLine("----------------------"); complexGraphics.Draw(); Console.WriteLine("復雜圖形的繪制完成"); Console.WriteLine("----------------------"); complexGraphics.Remove(line); Console.WriteLine("移除線段C后,復雜圖形的繪制如下:"); Console.WriteLine("---------------------"); complexGraphics.Draw(); Console.WriteLine("復雜圖形繪制完成"); Console.WriteLine("---------------------");
調用結果:

五、優缺點及適用場景
優點:
1)組合模式使得客戶端可以一致的處理對象和對象容器,既是葉節點和枝節點。
2)更容易的為組合對象添加新的組件。
3)解耦了客戶端與復雜對象。
缺點:
設計更加復雜。
適用場景:
1)需要表示一個對象整體和部分的層次結構
2)用戶希望忽略組合對象和單個對象的不同,一致的處理組合對象和單個對象。
新聞熱點
疑難解答