将对象组合成树形结构以表示 部分-整体 的层次结构。
比如这样的一个场景(书上的例子): 有text、line这样的一些图元,可以组合成较大的组件。而组合后的组件又可以组合成更大的组件。一种简单的实现,是为text、line定义一些类,另外定义一些类作为这些图元的容器类。这样的问题在于,图元与容器是两类对象,但是实际上组件应当具有图元的性质。
组合composite的关键就是一个抽象类,即可以代表图元,又可以代表图元的容器。
优点:
1 定义了包含基本对象和组合对象的类层次结构。 基本对象可以被组合成更复杂的组合对象。而组合对象又可以被组合,可以不断进行递归。
2 简化客户代码,客户可以对单个对象和组合对象不进行区分。
3 容易增加新的组件
4 设计变得一般化。 但是也就是意味着很难限制组合中的组件,比如只期望一个组合只能拥有特定的组件,这些只能运行时检查。
这个模式稍微复杂一些,参与者包括:
1 Component 基类
为所有的的对象声明接口;
适当情况下实现所有类共以后接口的缺省行为
声明一个接口用以访问和管理Compoent的子组件
可以在递归结构中定义一个接口用以访问一个父部件。
2 Leaf 最低层的子类
在组合中表示叶节点,叶节点没有子节点
定义叶子节点的行为
3 Composite
有子部件的那些部件的行为
存储子部件
实现Component接口中与子部件有关的操作
3 client 通过Component接口操纵组合部件的对象
Component 的困难主要在于实现出一个良好的体系,实现时需要考虑的地方包括:
1 显式的父部件引用。 通常在Compoent类中定义父部件的引用。 保持从子部件到父部件的引用能简化组合结构的遍历和管理。
父部件引用,需要保证同一个组合的所有子节点都以这个组合为层次。
2 共享组件 可以减少对存储的需求
3 最大化Component接口 Composite模式的目的之一是使得用户不知道他们正在使用的是具体的Leaf和Composite类。为此,Composite应当尽可能的多定义一些公共操作,并通常提供缺省实现。
而类的层次设计原则规定: 一个类只定义那些对它的子类有意义的操作。这里,访问子节点的接口是Component的一部分,但是对于Leaf类却不需要。
这里一种解决方法是:为Component定义一个缺省操作,对于子节点进行访问,缺省操作不返回。Leaf类可以使用默认实现,而Composite类则重新实现操作。
4 声明管理子部件的操作
透明性: 在Compoent定义管理子部件的add del方法。可以一致性的使用所有的组件,但是不安全,可能对leaf也使用add、del方法。
安全性: 在Composite类定义管理子部件的方法。这样缺失透明型。 Composite类与Compoent有不同的接口。
这里的一个解决方法是在父类增加Getposite方法,示例如下:
class Composite;
class Component {
public:
virtual Composite *GetComposite() { return NULL:}
};
class Composite : public Compoent {
virtual Composite *GetComposite() { return this:}
};
class Leaf : public Compoent {
};
这样对于客户,通过GetComposite来判断是否时候组合,从而选择是否使用管理方法。
提供透明性的唯一方式是在Component类中增加add 、del方法。那么对于Leaf Add会导致失败。可能会和客户的期望不同。
5 Component是否应该实现一个Component列表 在基类中将子节点集合定义为一个变量。但是对于叶节点是空间浪费。
6 子部件排序
7 使用高速缓存改善性能 Composite类可以缓存对其子节点进行遍历或者查找的相关信息。 一旦部件发生变化,父部件的缓存失效。需要顶一个接口来通知父部件缓存信息无效。
8 谁来删除Component 当一个Composite被销毁时,通常最好由Composite负责删除其子节点。
9 存储组件选用的数据结构 Composite的每个子类都可以有自己的 管理接口,自己的存储结构。