Composite组合(结构型模式)

问题
在面向对象系统中,我们常会遇到一类具有“容器”特征的对象---即它们在充当对象的同时,又是其他对象的容器。
动机
上述描述的问题根源在于:客户代码过多地依赖于对象容器复杂的内部实现结构,对象容器内部实现结构(而非抽象接口)的变化将引起客户代码的频繁变化,带来了代码的维护性、扩展性等弊端。
如何将“客户代码与复杂的对象容器结构”解耦?让对象容器自己来实现自身的复杂结构,从而使得客户代码就像处理简单对象一样来处理复杂的对象容器?
意图
将对象组合成树形结构以表示“部分-整体”的层次结构。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模式在具体实现中,可以让父对象中的子对象反追溯;如果父对象有频繁的遍历需求,可使用缓存技巧来改善效率。

posted on 2006-03-28 22:39  蝈蝈  阅读(397)  评论(0)    收藏  举报