一、定义
组合模式:将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
解释:简单来说,编写一个类,该类能作用于整体,并且编写整体中的部分时也能使用该类,而不用做大的更改。
二、UML类图及基本代码
基本代码:
abstractclassComponent
{PRotectedstringname;publicComponent(stringname)
{this.name =name;
}publicabstractvoidAdd(Component component);publicabstractvoidRemove(Component component);publicabstractvoidDisplay(intdepth);
}classLeaf : Component
{publicLeaf(stringname)
:base(name)
{ }publicoverridevoidAdd(Component component)
{
Console.WriteLine("cannot add to a leaf");
}publicoverridevoidRemove(Component component)
{
Console.WriteLine("cannot remove to a leaf");
}publicoverridevoidDisplay(intdepth)
{
Console.WriteLine(newstring('-', depth) +name);
}
}classComposite : Component
{privateIList<Component> children =newList<Component>();publicComposite(stringname)
:base(name)
{ }publicoverridevoidAdd(Component component)
{
children.Add(component);
}publicoverridevoidRemove(Component component)
{
children.Remove(component);
}publicoverridevoidDisplay(intdepth)
{
Console.WriteLine(newstring('-', depth) +name);foreach(Component componentinchildren)
{
component.Display(depth+2);
}
}
}
客户端进行调用:
Composite root =newComposite("root");
root.Add(newLeaf("leaf A"));
root.Add(newLeaf("leaf B"));
Composite composite=newComposite("Composite X");
composite.Add(newLeaf("leaf XA"));
composite.Add(newLeaf("leaf XB"));
root.Add(composite);
Composite composite2=newComposite("Composite XY");
composite2.Add(newLeaf("leaf XYA"));
composite2.Add(newLeaf("leaf XYB"));
composite.Add(composite2);
root.Add(newLeaf("leaf C"));
Leaf leaf=newLeaf("Leaf D");
root.Add(leaf);
root.Remove(leaf);
root.Display(1);
View Code
结果如图:
三、透明方式和安全方式
基本代码中,leaf类也有add和remove方法,也就是说Component声明所有用来管理子对象的方法,实现了所有子类都具备其方法的目的。这样做的好处就是叶节点和枝节点对于外界没有区别,它们具备完全一致的行为接口。但因为leaf不具备add和remove的功能,所以实现它是没有意义的。这种方式就是透明方式。
安全方式是叶节点和枝节点不具有相同的接口,由于不够透明,那么客户端调用时需要做相应的判断,带来了不便。所以在实际项目中使用安全方式和透明方式就需要视情况而定。
四、举例说明:
绘制一个图形,该图形由一个复杂图形和两条线段组成。可以自由的移除该图形。
publicabstractclassGraphics
{publicstringName {get;set; }publicGraphics(stringname)
{this.Name =name;
}publicabstractvoidDraw();publicabstractvoidAdd(Graphics graphics);publicabstractvoidRemove(Graphics graphics);
}publicclassLine : Graphics
{publicLine(stringname)
:base(name)
{ }publicoverridevoidDraw()
{
Console.WriteLine("画"+Name);
}publicoverridevoidAdd(Graphics graphics)
{thrownewException("不能向简单图形line添加图形");
}publicoverridevoidRemove(Graphics graphics)
{thrownewException("不能向简单图形line移除图形");
}
}publicclassCircle : Graphics
{publicCircle(stringname)
:base(name)
{ }publicoverridevoidDraw()
{
Console.WriteLine("画"+Name);
}publicoverridevoidAdd(Graphics g)
{thrownewException("不能向简单图形Circle添加其他图形");
}publicoverridevoidRemove(Graphics g)
{thrownewException("不能向简单图形Circle移除其他图形");
}
}publicclassComplexGraphics : Graphics
{privateIList<Graphics> complexGraphicsList =newList<Graphics>();publicComplexGraphics(stringname)
:base(name)
{ }publicoverridevoidDraw()
{foreach(Graphics gincomplexGraphicsList)
{
g.Draw();
}
}publicoverridevoidAdd(Graphics graphics)
{
complexGraphicsList.Add(graphics);
}publicoverridevoidRemove(Graphics graphics)
{
complexGraphicsList.Remove(graphics);
}
}
客户端调用:
ComplexGraphics complexGraphics =newComplexGraphics("一个复杂图形和两条线段组成的复杂图形");
complexGraphics.Add(newLine("线段A"));
ComplexGraphics complexGraphics2=newComplexGraphics("一个圆和一条线组成的复杂图形");
complexGraphics2.Add(newCircle("圆"));
complexGraphics2.Add(newLine("线段B"));
complexGraphics.Add(complexGraphics2);
Line line=newLine("线段C");
complexGraphics.Add(line);
Console.WriteLine("复杂图形的绘制如下:");
Console.WriteLine("----------------------");
complexGraphics.Draw();
Console.WriteLine("复杂图形的绘制完成");
Console.WriteLine("----------------------");
complexGraphics.Remove(line);
Console.WriteLine("移除线段C后,复杂图形的绘制如下:");
Console.WriteLine("---------------------");
complexGraphics.Draw();
Console.WriteLine("复杂图形绘制完成");
Console.WriteLine("---------------------");
View Code
调用结果:
五、优缺点及适用场景
优点:
1)组合模式使得客户端可以一致的处理对象和对象容器,既是叶节点和枝节点。
2)更容易的为组合对象添加新的组件。
3)解耦了客户端与复杂对象。
缺点:
设计更加复杂。
适用场景:
1)需要表示一个对象整体和部分的层次结构
2)用户希望忽略组合对象和单个对象的不同,一致的处理组合对象和单个对象。