1 意图
将对象组合成树形结构以表示“部分-整体”的层次结构。Composite 使得用户对单个对象和组合对象的使用具有一致性。
2 别名
无
3 动机
在绘图编辑器和图形捕捉系统这样的图形应用程序中,用户可以使用简单的组件创建复杂的图表。用户可以组合多个简单组件以形成一些较大的组件,这些组件又可以组合成更大的组件。一个简单的实现方法是为 Text 和 Line 这样的图元定义一些类,另外定义一些类作为这些图元的容器类(Container)。问题:使用这些类的代码必须区别对待图元对象与容器对象,而实际上大多数情况下用户认为它们是一样的。
4 适用性
- 你想表示对象的部分 -整体层次结构。
- 你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
5 结构
6 参与者
- Component(Graphic)
- 为组合中的对象声明接口。
- 在适当的情况下,实现所有类共有接口的缺省行为。
- 声明一个接口用于访问和管理 Component 的子组件。
- (可选)在递归结构中定义一个接口,用于访问一个父部件,并在合适的情况下实现它。
- Leaf(Rectangle、Line、Text 等)
- 在组合中表示叶节点对象,叶节点没有子节点。
- 在组合中定义图元对象的行为。
- Composite(Picture)
- 定义有子部件的那些部件的行为。
- 存储子部件。
- 在 Component 接口中实现与子部件有关的操作。
- Client
- 通过 Component 接口操纵组合部件的对象。
7 协作
用户使用 Component 类接口与组合结构中的对象进行交互。如果接收者是一个叶节点 ,则直接处理请求。如果接收者是 Composite , 它通常将请求发送给它的子部件,在转发请求之前与/或之后可能执行一些辅助操作。
8 效果
- 定义了包含基本对象和组合对象的类层次结构
- 简化客户代码
- 使得更容易增加新类型的组件
- 使你的设计变得更加一般化
- 子部件排序
9 实现
- 显式的父部件引用
- 共享组件
- 最大化 Component 接口
- 声明管理子部件的操作(透明性 or 安全性)
- Component 是否应该实现一个 Component 列表
- 应该由谁删除 Component
- 存贮组件最好用哪一种数据结构(列表、树、数组和 hash 表,效率)
10 代码示例
Component
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19class Component
{
public abstract void Operation();
public virtual void Add(Component component)
{
//默认实现,Leaf不需要复写,Composite需要复写
}
public virtual void Remove(Component component)
{
//默认实现,Leaf不需要复写,Composite需要复写
}
public virtual Component GetChild(int index)
{
//默认实现,Leaf不需要复写,Composite需要复写
}
}Leaf(Rectangle、Line、Text 等)
1
2
3
4
5
6
7class Leaf:Component
{
public override void Operation()
{
Console.WriteLine("Leaf");
}
}Composite(Picture)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27class Composite:Component
{
private List<Component> children=new List<Component>();
public override void Operation()
{
foreach(var component in children)
{
component.Operation();
}
}
public new void Add(Component component)
{
children.Add(component);
}
public new void Remove(Component component)
{
children.Add(component);
}
public new Component GetChild(int index)
{
return children[index];
}
}Client
1
2
3
4
5
6
7
8
9
10
11
12class Client
{
public static void Main(string[] args)
{
Component leaf=new Leaf();
leaf.Operation();
Component composite=new Composite();
composite.Add(leaf);
composite.Operation();
}
}
11 已知应用
MVC 中的 View。
12 相关模式
- 通常部件 - 父部件连接用于 Responsibility of Chain 模式。
- Decorator 模式经常与 Composite 模式一起使用。当装饰和组合一起使用时,它们通常有一个公共的父类。因此装饰必须支持具有 Add、Remove 和 GetChild 操作的 Component。
- Flyweight 让你共享组件,但不再能引用他们的父部件。
- Itertor 可用来遍历 Composite。
- Visitor 将本来应该分布在 Composite 和 Leaf 类中的操作和行为局部化。