问题在面向对象系统中,我们常会遇到一类具有“容器”特征的对象---即它们在充当对象的同时,又是其他对象的容器。动机上述描述的问题根源在于:客户代码过多地依赖于对象容器复杂的内部实现结构,对象容器内部实现结构(而非抽象接口)的变化将引起客户代码的频繁变化,带来了代码的维护性、扩展性等弊端。如何将“客户代码与复杂的对象容器结构”解耦?让对象容器自己来实现自身的复杂结构,从而使得客户代码就像处理简单对象一样来处理复杂的对象容器?意图将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。代码public interface IBox{ void Process();}public class SingleBox:IBox{ public void Process() { ... }}public class ContainerBox:IBox{ public void Process(){} public ArrayList GetBoxes(){}}public class App{ public static void Main() { IBox box = Factory.GetBox(); if(box is ContainerBox) { //问题:客户代码与对象内部结构耦合太紧 box.Process(); ArrayList list = ((ContrainerBox)box)GetBoxes(); //接下来将面临比较复杂的递归处理 } else { box.Process(); } }}改进...(客户代码仅与抽象接口耦合)public class App{ public static void Main() { IBox box = Factory.GetBox(); box.Process(); }}public class ContainerBox:IBox{ ArrayList list = null; public void Add(IBox box) { if(list == null) { list = new ArrayList(); } else{ list.Add(box); } } public void Remove(IBox box) { if(list == null) { throw new Excepion(); } list.Remove(box); } public void Process() { //1.do something...
//2.do process for the box in the list if(list != null) { foreach(IBox box in list) { box.Process(); //其实是递归调用 } } }}改进...(统一处理SingleBox和ContrainerBox)public interface IBox{ void Process(); void Add(IBox box); void Remove(IBox box);}public class SingleBox:IBox{ public void Process() { ... } public void Add(IBox box) { //抛出异常 } public void Remove(IBox) { //抛出异常 }}其实就是一个树型结构,SingleBox是叶子结点,ContrainerBox是树枝。其实可以把SingleBox和ContrainerBox都当作是容器。UML要点Composite模式采用树形结构来实现普遍存在的对象容器,从而将一对多的关系转化为一对一的关系,使得客户代码可以一致地处理对象和对象容器,无需关心处理的是单个对象还是组合的对象容器。将“客户代码与复杂的对象容器结构”解耦是Composite模式的核心思想,解耦之后,客户代码将纯粹的抽象接口--而非对象容器的复杂内部实现结构--发生依赖关系,从而更能应对变化。Composite模式中,是将Add和Remove等和对象容器相关的方法定义在表示抽象对象的Component类中,还是将其定义在表示对象容器的Composite类中,是一个关于透明性和安全性的两难问题,需要仔细权衡。这里有可能违背面向对象的单一职责原则,但是对于这种特殊结构,这又是必须付出的代价。Asp.net控件的实现在这方面为我们提供了一个很好的示范。Composite模式在具体实现中,可以让父对象中的子对象反追溯;如果父对象有频繁的遍历需求,可使用缓存技巧来改善效率。
转载于:https://www.cnblogs.com/hotsoho.net/articles/361318.html