Composite(组合)模式(对象结构型模式)
一. 意图
将对象组合成树形结构以表示"部分-整体"的层次结构. Composite使得用户对单个对象和组合对象的使用具有一致性.
二. 适用性
1. 你想表示对象的部分-整体层次结构.
2. 你希望用户忽略组合对象与单个对象的不同, 用户将统一地使用组合结构中的所有对象.
三. 模式结构
图1
四. 角色说明
Component
—为组合中的对象声明接口.
—在适当的情况下, 实现所有类共有接口的缺省行为.
—声明一个接口用于访问和管理Component的子组件(这里的GetChild(int)).
—(可选)在递归结构中定义一个接口, 用于访问一个父部件, 并在合适的情况下实现它.
Leaf
—在组合中表示叶节点对象, 叶节点没有子节点.
—在组合中定义原子对象的行为.
Composite
—定义有子部件的那些部件的行为.
—存储子部件。
—在Component接口中实现与子部件有关的操作.
Client
—通过Component接口操纵组合部件的对象. 对于Client来说操作组合部件与树叶部件是没有区别的.
五. 说明
1. 定义了包含基本对象和组合对象的类层次结构 基本对象可以被组合成更复杂的组合对象, 而这个组合对象又可以被组合, 这样不断的递归下去. 客户代码中, 任何用到基本对象的地方都可以使用组合对象.
2. 简化客户代码 客户可以一致地使用组合结构和单个对象。通常用户不知道(也不关心)处理的是一个叶节点还是一个组合组件。这就简化了客户代码. 但是如果你的需求中需要区分时, 你需要使用一定的方法去区分是一个叶组件还是组合组件.
3. 使得更容易增加新类型的组件新定义的Composite或Composite子类自动地与已有的结构和客户代码一起工作,客户程序不需因新的Component类而改变(例如你可以增加一个组合组件, 这个组合组件是由其他的组合组件组成)
4. 使你的设计变得更加一般化, 容易增加新组件也会产生一些问题, 那就是很难限制组合中的组件. 有时你希望一个组合只能有某些特定的组件. 使用Composite时, 你不能依赖类型系统施加这些约束, 而必须在运行时刻进行检查.
5. Component中的接口是Leaf类接口加上Composite的接口. 这有时可能会与类层次结构设计原则相冲突, 该原则规定: 一个类只能定义那些对它的子类有意义的操作. 有许多Component所支持的操作对Leaf类似乎没有什么意义, 那么可以在Component对这些接口进行缺省操作.
6. 组合组件需要定制一定的策略来管理其子组件. 看你的需求.
7. 这里的子组件不知道其父组件.
六. 我的理解
例如 一个矢量图系统, 有点, 圆形, 直线(线段), 矩形, 圆弧, 多边形, 不规则图形组成.
很明显 点, 可以作为Leaf
直线: 两个点
圆形: 点 + 半径
圆弧: 圆心 + 始末点 + 方向
矩形: 两个对角点.
多边形:直线(或者点)(看你的需求, 你可以使用一个直线的列表或者使用点的列表来存储多边形).
不规则图形: 直线 + 圆弧
当你需要绘制这些图形的时候就可以使用Composite模式.
这里只使用Composite模式可能不一定能满足需求, 例如Component的Draw函数, 有时为了提套绘图效率, 我们可能不是简单的调用Draw函数, 而是需要判断一下对象的类型来做对应的优化等. Component的子组件不知道它的父组件.
七. 相关模式
1. 通常部件-父部件连接用于Responsibility of Chain模式.
2. Decorator模式经常与Composite模式一起使用. 当装饰和组合一起使用时,它们通常有一个公共的父类. 因此装饰必须支持具有Add、Remove和GetChild操作的Component接口.
3. Flyweight让你共享组件, 但不再能引用他们的父部件.
4. Itertor可用来遍历Composite.
5. Visitor将本来应该分布在Composite和Leaf类中的操作和行为局部化.