说明动机:
* 在面向对象系统中,我们常常会遇到一类具有“容器”特征的对象——即他们在充当对象的同时
* ,又是其他对象的容器。例如:
* public class SingleBox:IBox public class ContainerBox:IBox
* { {
* public void Process(){....} public void Process(){....}
* } public ArrayList GetBoxes(){....}
* }
* 如何我们要对这样的对象容器进行处理:
* IBox box=Factory.GetBox();
* if(box is ContainerBOx)
* {box.Process();ArrayList list=((ContainerBox)box).GetBoxes();...//将面临比较复杂的递归处理}
* else if(box is SingleBox){box.Process();}
* 这样的处理过程显然将其类结构过多的暴露给客户,而且让客户的代码依赖于对象容器复杂的内部实现结构;
* 对象容器内部实现结构(而非抽象接口)的变化将引起客户代码的频繁变化,带来了代码的维护性、扩展性等
* 弊端。如何将“客户代码与复杂的对象容器结构”解耦?让对象容器自己来实现自身的复杂结构,从而使得客
* 户代码就像处理简单对象一样来处理复杂的对象容器
意图:将对象组合成树形结构以表示“部分”与“整体”的层次结构。组合模式是使得用户 对单个对象和组合对象的使用一致性。
可适用性:
- 你想表示对象的部分-整体层次结构。
- 你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
UML图解:
示例代码:
1 namespace Composite //示例代码 2 { 3 /// <summary> 4 /// 树容器对象接口 5 /// </summary> 6 public abstract class IBox 7 { 8 9 public abstract void Process(); 10 public abstract void Add(IBox box); 11 public abstract void Remove(IBox box); 12 public abstract IBox GetChild(int index); 13 } 14 15 /// <summary> 16 /// 单个容器(里面没有子容器) 17 /// </summary> 18 public class SingleBox : IBox 19 { 20 21 public override void Process() 22 { 23 //do something processing... 24 25 } 26 27 public override void Add(IBox box) 28 { 29 throw new NotSupportedException(); 30 } 31 32 public override void Remove(IBox box) 33 { 34 throw new NotSupportedException(); 35 } 36 37 public override IBox GetChild(int index) 38 { 39 return this; 40 } 41 } 42 43 /// <summary> 44 /// 容器(有子容器) 45 /// </summary> 46 public class ContainerBox : IBox 47 { 48 ArrayList boxList = null; 49 50 public override void Process() 51 { 52 //do process for myself。。 53 //...... 54 //do process for the box in boxList 55 foreach (IBox item in boxList) 56 { 57 item.Process(); 58 } 59 } 60 61 public override void Add(IBox box) 62 { 63 if (boxList == null) 64 { 65 boxList = new ArrayList(); 66 } 67 boxList.Add(box); 68 } 69 70 public override void Remove(IBox box) 71 { 72 boxList.Remove(box); 73 } 74 75 public override IBox GetChild(int index) 76 { 77 if (boxList == null) 78 { 79 throw new NullReferenceException(); 80 } 81 else if (index < 0 || index > boxList.Count) 82 { 83 throw new ArgumentOutOfRangeException(); 84 } 85 return (IBox)boxList[index]; 86 } 87 } 88 89 public class App 90 { 91 public static void Main() 92 { 93 IBox box = new ContainerBox(); 94 box.Add(new SingleBox()); 95 box.Add(new ContainerBox()); 96 97 box.Process();//这样客户只需调用Process()方法就足够处理每个子容器了 98 } 99 } 100 101 }
Composite模式的几个要点 :
1、Composite模式采用树形结构来实现普遍存在的对象容器,从而将“一对多”的关系 转化为“一对一”的关系,使得客户代码可以一致地处理对象和对象容器,无需关系处理 的是单个对象,还是组合的对象容器。
2、将“客户代码与复杂的对象容器结构”解耦是Composite模式的核心思想,解耦之后,客户代码 * 将于纯粹的抽象接口——而非对象容器的复杂内部实现结构——发生依赖关系,从而更能“应对变化”
3、Composite模式中,是将Add和Remove等和对象容器相关的方法定义在了表示抽象对象的Component类中 ,还是将其定义在表示对象容器的Composite类中,是一个关乎透明性和安全性的两难问题,需要仔细权衡 。这里有可能违背面向对象的“单一职责原则”,但是对于这种特殊结构,这又是必须付出的代价。ASP.NET 控件的实现在这方面为我们提供了一个很好的示范。
4、Composite模式在具体实现中,可以让父对象中的子对象反向追溯;如果父对象有频繁的遍历要求,可使用缓存技巧改善效率
注:本示例代码是本人学习Webcast C#面向对象设计模式纵横谈系列讲座视频时,跟着李建忠老师一步一步的编写的,在此奉献出来,仅供大家参考