一、定义
组合模式:将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
解释:简单来说,编写一个类,该类能作用于整体,并且编写整体中的部分时也能使用该类,而不用做大的更改。
二、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); } } }
客户端进行调用:
logs_code_hide('3a4e38b7-0455-47bc-931f-cdc34aaffc4e',event)" src="/Upload/Images/2014112812/2B1B950FA3DF188F.gif" alt="" />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);View Code
结果如图:
三、透明方式和安全方式
基本代码中,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("---------------------");View Code
调用结果:
五、优缺点及适用场景
优点:
1)组合模式使得客户端可以一致的处理对象和对象容器,既是叶节点和枝节点。
2)更容易的为组合对象添加新的组件。
3)解耦了客户端与复杂对象。
缺点:
设计更加复杂。
适用场景:
1)需要表示一个对象整体和部分的层次结构
2)用户希望忽略组合对象和单个对象的不同,一致的处理组合对象和单个对象。