一、概述
在软件开发中,我们往往会遇上类似树形结构的对象体系。即某一对象既可能在树形结构中作为叶节点存在,也可能作为分支节点存在。比如在文件系统中,文件是作为叶节点存在,而文件夹就是分支节点。在设计这类对象时,如果将叶节点和分支节点区别对待,那么在实际开发中会带来较大的复杂性。比如客户端调用时可能会频繁的使用转型操作,同时代码的可维护性和扩展性也较差。在设计中使用组合模式可以解决这一系列弊端。
二、组合模式
组合模式定义了叶节点和分支节点的一致的接口,将客户端代码与复杂的对象结构解耦,大大降低了客户端调用的复杂性。其结构图如下:
Component定义了所有对象的共同接口,可以在Component中定义管理Component组件的接口以保证一致性,也可以将管理接口下放至Composite中以提高系统调用的安全性。
Leaf表示叶节点。
Composite定义了分支节点对象的行为,并提供一个容器用户存储其子节点。
Client通过Component来处理所有对象。
三、示例
我们利用组合模式来实现一个绘图系统。在该系统中具有Line、Circle、Picture等多种元素,其中Picture可以含有各类子元素。
首先定义Component。
1 public abstract class Graphic 2 { 3 private string _name; 4 5 public Graphic(string name) 6 { 7 _name = name; 8 } 9 10 public abstract void Add(Graphic graphic); 11 public abstract void Remove(Graphic graphic); 12 13 public virtual void Draw() 14 { 15 Console.WriteLine("Draw {0} {1}", GetType().Name, _name); 16 } 17 }
接着定义Picture对象。
1 public class Picture : Graphic 2 { 3 private List<Graphic> _graphic = new List<Graphic>(); 4 public Picture(string name) 5 : base(name) 6 { 7 } 8 9 public override void Add(Graphic graphic) 10 { 11 _graphic.Add(graphic); 12 } 13 public override void Remove(Graphic graphic) 14 { 15 _graphic.Remove(graphic); 16 } 17 18 public override void Draw() 19 { 20 base.Draw(); 21 foreach (Graphic graphic in _graphic) 22 { 23 graphic.Draw(); 24 } 25 } 26 }
再定义Line和Circle。
1 public class Line : Graphic 2 { 3 public Line(string name) 4 : base(name) 5 { 6 } 7 8 public override void Add(Graphic graphic) 9 { 10 throw new Exception("Line can't add graphic"); 11 } 12 public override void Remove(Graphic graphic) 13 { 14 throw new Exception("Line can't remove graphic"); 15 } 16 } 17 18 public class Circle : Graphic 19 { 20 public Circle(string name) 21 : base(name) 22 { 23 } 24 25 public override void Add(Graphic graphic) 26 { 27 throw new Exception("Circle can't add graphic"); 28 } 29 public override void Remove(Graphic graphic) 30 { 31 throw new Exception("Circle can't remove graphic"); 32 } 33 }
这样就可以通过统一的Draw接口画出整幅图画。