意图
- 将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。
适用性
- 想表示对象的部分-整体层次机构
- 希望忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
结构
参与者
- Component
- 为组合中的对象声明接口
- 在适当的情况下,实现所有类共有接口的缺省行为
- 声明一个接口用于访问和管理Component的子组件
- 在递归结构中定义一个接口,用于访问一个父部件,并在合适的情况下实现它
- Leaf
- 在组合中表示叶节点对象,叶节点没有子节点
- 在组合中定义图元对象的行为
- Composite
- 定义有子部件的那些部件的行为
- 存储子部件
- 在Component接口中实现与子部件有关的操作
- Client
- 通过Component接口操纵组合部件的对象
效果
- 定义了包含基本对象和组合对象的类层次结构
- 简化客户代码
- 使得更容易增加新类型的组件
- 使得设计更一般化
实现
- 显式的父部件引用
- 共享组件
- 最大化Component接口
- 声明管理子部件的操作
- Component是否应该实现一个Component列表
- 子部件排序
- 使用高速缓冲存储改善性能
- 应该由谁删除Component
- 存储组件最好用哪一个数据结构
代码实现
class Client
{
public void Test()
{
Component ca = new LeafA();
Component cb = new LeafB();
Component cc = new Composite();
cc.Add(ca);
cc.Add(cb);
cc.Operation();
}
}
abstract class Component {
protected List<Component> list = new List<Component>();
public abstract void Operation();
public abstract void Add(Component c);
public abstract void Remove(Component c);
public abstract Component GetChild(int i);
}
class LeafA : Component
{
public override void Operation()
{
Console.WriteLine(this.GetType().Name);
//return this.GetType().Name;
}
public override void Add(Component c)
{
}
public override Component GetChild(int i)
{
return null;
}
public override void Remove(Component c)
{
}
}
class LeafB : Component
{
public override void Operation()
{
Console.WriteLine(this.GetType().Name);
//return this.GetType().Name;
}
public override void Add(Component c)
{
}
public override Component GetChild(int i)
{
return null;
}
public override void Remove(Component c)
{
}
}
class Composite : Component
{
public override void Operation()
{
foreach (var value in list)
{
value.Operation();
}
}
public override void Add(Component c)
{
list.Add(c);
}
public override void Remove(Component c)
{
list.Remove(c);
}
public override Component GetChild(int i)
{
if (list.Count < i)
throw new Exception();
return list[i];
}
}
相关模式
通常部件-父部件连接用于Responsibility of Chain模式;Decorator模式经常与Composite模式一起使用。当装饰和组合一起使用时,它们通常有一个公共的父类。因此装饰必须支持具有Add,GetChild,Remove操作Component的接口。Flyweight让你共享组件,但不再能引用它们的父类。Itertor可用于遍历Composite。Visitor将本来因该分布在Composite和leaf类中的操作和行为局部化。