Design Patterns之Composite Pattern总结

  本文总结一下今天学习的Composite(组合)模式。内容主要基于李建忠WebCast《C#面向对象设计模式纵横谈》。
首先,看一下Composite模式的意图: 将对象组合成树形结构以表示“部分-整体”的层次结构。Composite模式使得用户对单个对象和组合对象的使用具有一致性。――GOF 《设计模式》
  我们看这们个例子:我们有两类盒子,设为A类和B类,A类盒子的内部还装有盒子,而B类盒子内部不能装盒子,A类盒内部装的盒子既可以是A类的也可以是B类的,假设现在桌子上放有许多盒子(可能是A类或B类盒子),要求计算桌子上的总盒子数,如果是A类盒子,则需要算上它内部的盒子数,比如桌上有1个A类盒子box1和1个B类盒子box2,A类盒子内有1个B类盒子box3和1个A类盒子box4,这个box4内又装有3个B类盒子box5,box6,box7,那么总盒子数就是7。

  那现在要怎么做呢?A、B两类盒子都是盒子,那我们就定义一个盒子接口,GetBoxCount()方法将返回此盒子内的所有盒子数。

public   interface  IBox
{
   
//取得盒子总数
   int GetBoxCount();
}

然后是A类和B类盒子:
/// <summary>
/// 表示B类盒子,内部不能再装盒子,用SingleBox作类名,一会不容易搞混
/// </summary>

public   class  SingleBox : IBox
{
    
//取得盒子总数
     public int GetBoxCount()
    
{
    
return 1;
    }

}

/// <summary>
/// A类盒子,内部可再装盒子,用“盒子容器”作类名
/// </summary>

public   class  BoxContainer : IBox
{
    
//private List<SingleBox> boxes;
    private List<IBox> boxes;
    
//添加盒子
    public void Add(IBox box)
    
{
        
if (boxes == null)
        
{
            
//boxes = new List<SingleBox>();
        boxes = new List<IBox>();
        }

        boxes.Add(box);
        }

    
//删除盒子
    public void Remove(IBox box)
    
{
        
if ( (boxes == null|| (boxes.Count == 0) )
        
{
            
throw new Exception("Sorry,已经没有盒子可Remove了");
        }

        boxes.Remove(box);
    }

    
//取得盒子总数
    public int GetBoxCount()
    
{
        
int count = 1//因为BoxContainer本身就是一个盒子,所以初始化为1
        if ( (boxes != null&& (boxes.Count > 0) )
        
{
            
foreach (IBox box in boxes)
            
{
                count 
+= box.GetBoxCount();
            }

        }

        
return count;
    }

}

然后就可以在Main()方法中测试了:
public   static   void  Main( string [] args)
{
    
//新建4个内部不能装盒子的盒子
    IBox box1 = new SingleBox();
    IBox box2 
= new SingleBox();
    IBox box3 
= new SingleBox();
    IBox box4 
= new SingleBox();
    
//新建 2个内部可以装盒子的盒子
    BoxContainer boxContainer1 = new BoxContainer();
    BoxContainer boxContainer2 
= new BoxContainer();
    
//把box2,box3装入boxContainer2
    boxContainer2.Add(box2);
    boxContainer2.Add(box3);
    
//把box4和boxContainer2装入boxContainer1
    boxContainer1.Add(box4);
    boxContainer1.Add(boxContainer2);
    
//求总盒子数并输出
    int total = box1.GetBoxCount() + boxContainer1.GetBoxCount();
    Console.WriteLine(
"Total:{0}", total);
}

我们可以得到结果:Total:6
可以看到,虽然A类和B类是不同的盒子,但客户程序却可以不去理会盒子内部还有没有装盒子,装的是什么盒子,只要简简单单地调用GetBoxCount()方法。这样的话,客户程序就可以跟A类盒子(内部可以再装盒子)的内部结构解耦。BoxContainer类就是Composite模式中的组合类,它内部可以再装有盒子。
同时注意到BoxContainer类的私有成员boxes是被声明为List ,而不是注释中的List ,虽然本例中声明为List 也可以,但是当B类盒子不只一种时就不行了,声明为List 也体现了面向对象程序设计中依赖抽象而不是依赖实现的思想。
上面的Composite模式叫安全的Composite模式(为什么叫安全的?在段尾见答案),因为对于SingleBox来说,内部不能装盒子,所以没有Add和Remove方法,而BoxContainer有,但这种模式却导致了SingleBox和BoxContainer的接口不一致。还有一种Composite模式叫透明的Composite模式,它把Add和Remove等这些操作子对象的方法定义在IBox接口中,这样接口就一致了(比如在Main方法中就都可以用IBox来声明一个BoxContainer了:IBox boxContainer1 = new BoxContainer();),但是SingleBox里用Add和Remove明显是不行的,所以,在SingleBox的Add和Remove方法中都抛出一个异常,而在安全的Composite模式中是没有这个问题的,所以才叫安全的Composite模式。在实际应用中选择哪种Composite模式,要根据具体情况来看,其实也就是权衡安全性和透明性的问题了。

总 结:
1. Composite(组合)模式解耦了客户程序与复杂元素内部结构,从而使客户程序可以像处理简单元素一样来处理复杂元素。
2. 有安全型的Composite模式和透明型的Composite模式,在它们中做选择也就是在安全性和透明性中找个平衡点。

你可能感兴趣的:(design pattern)