一、简介(Brief Introduction)
将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
例子1:就是多级树形菜单。
例子2:文件和文件夹目录。
例子3:部门的各层管理(学校和企业均可)
二、模式分析(Analysis)
抽象构件角色(component)是组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理Component子部件。这个接口可 以用来管理所有的子对象。(可选)在递归结构中定义一个接口,用于访问一个父部件,并在合适的情况下实现它。
树叶构件角色(Leaf):在组合树中表示叶节点对象,叶节点没有子节点。并在组合中定义图元对象的行为。
树枝构件角色(Composite):定义有子部件的那些部件的行为。存储子部件。在Component接口中实现与子部件有关的操作。
客户角色(Client):通过component接口操纵组合部件的对象。
三、案例分析(Example)
1) 将管理子元素的方法定义在Composite类中
2) 将管理子元素的方法定义在Component接口中,这样Leaf类就需要对这些方法空实现。
namespace 组合模式
{
1、客户端
class Program
{
static void Main(string[] args)
{
Composite root = new Composite("root"); //生成树根root,根上长出两叶LeafA和LeafB
root.Add(new Leaf("Leaf A"));
root.Add(new Leaf("Leaf B"));
Composite comp = new Composite("Composite X"); //根上长出CompositeX,分支上也有两叶LeafXA和LeafXB
comp.Add(new Leaf("Leaf XB"));
comp.Add(new Leaf("Leaf XA"));
root.Add(comp);
Composite comp2 = new Composite("Composite XY"); //在CompositeX上又长出分支CompositeXY,分支上也有两叶LeafXYA和LeafXYB
comp2.Add(new Leaf("Leaf XYA"));
comp2.Add(new Leaf("Leaf XYB"));
comp.Add(comp2);
root.Add(new Leaf("Leaf C")); //根上又长出LeafC和LeafD,LeafD没长牢,被风吹走了
Leaf leaf = new Leaf("Leaf D");
root.Add(leaf);
root.Remove(leaf);
root.Display(1); //显示大树
Console.Read();
}
}
2、声明一个接口
用于管理Component的子部件
abstract class Component
{
protected string name;
public Component(string name)
{
this.name = name;
}
public abstract void Add(Component c); //用Add和Remove方法提供增加或移除树叶或树枝的功能
public abstract void Remove(Component c);
public abstract void Display(int depth);
}
3、叶节点
class Leaf : Component //由于叶节点没有增加分支和树叶的功能,这样做可以消除叶节点和枝节点对象在抽象层次的区别,它们具有完全一致的接口
{
public Leaf(string name)
: base(name)
{ }
public override void Add(Component c)
{
Console.WriteLine("Cannot add a leaf");
}
public override void Remove(Component c)
{
Console.WriteLine("Cannot remove a leaf");
}
public override void Display(int depth) //叶节点的具体方法,此处是显示名称和级别
{
Console.WriteLine(new String('-', depth) + name);
}
}
4、Composite定义有枝节点行为,用来存储子部件,在Compoent接口中实现与子部件有关的操作,比如增加Add和删除Remove。
class Composite : Component
{
private List<Component> Children = new List<Component>(); //一个子对象集合用来存储其下属的枝节点和叶节点
public Composite(string name)
: base(name)
{ }
public override void Add(Component c)
{
Children.Add(c);
}
public override void Remove(Component c)
{
Children.Remove(c);
}
public override void Display(int depth)
{
Console.WriteLine(new string('-', depth) + name); //显示枝节点名称,并对其下级进行遍历
foreach (Component component in Children)
{
component.Display(depth + 2);
}
}
}
四、解决的问题(What To Solve)
(1)你想表示对象的部分-整体层次结构
(2)你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
组合模式让你可以优化处理递归或分级数据结构。有许多关于分级数据结构的例子,使得组合模式非常有用武之地。关于分级数据结构的一个普遍性的例子是你每次使用电脑时所遇到的:文件系统。文件系统由目录和文件组成。每个目录都可以装内容。目录的内容可以是文件,也可以是 目录。按照这种方式,计算机的文件系统就是以递归结构来组织的。如果你想要描述这样的数据结构,那么你可以使用组合模式Composite。
五、优缺点(Advantage and Disadvantage)
优点:
1. 组合模式可以很容易的增加新的构件。
2.使用组合模式可以使客户端变的很容易设计,因为客户端可以对组合和叶节点一视同仁。
缺点:
1.使用组合模式后,控制树枝构件的类型不太容易。
2. 用继承的方法来增加新的行为很困难。
六、联系(Link)
1、装饰模式;经常与Composite模式一起使用。当装饰和组合一起使用时,它们通常有一个公共的父类。因此装饰必须支持具有 Add、Remove和GetChild 操作的Component接口。
2、享元模式:让你共享组件,但不再能引用他们的父部件。
3、迭代器模式:可用来遍历Composite。
4、观察者模式:将本来应该分布在Composite和Le a f类中的操作和行为局部化
七、总结(Summary)
组合模式解耦了客户程序与复杂元素内部结构,从而使客户程序可以向处理简单元素一样来处理复杂元素。
如果你想要创建层次结构,并可以在其中以相同的方式对待所有元素,那么组合模式就是最理想的选择。