Java设计模式 —— 组合模式
11 组合模式
11.1 组合模式概述
Composite Pattern: 组合多个对象形成树形结构以表示具有部分-整体关系的层次结构。组合模式使得客户端可以统一处理单个对象和组合对象。
组合模式关注那些包含叶子构件和容器构件的结构以及它们的组织形式,在叶子构件中不包含成员对象,而容器构建中可以包含成员对象,这些对象通过递归组合构成一个树形结构。组合模式为叶子构件和容器构件提供一个公共的抽象类,客户端可以针对抽象类编程,而无须关心操作的是叶子构件还是容器构件。
组合模式结构图如下所示:
需要注意的是虽然这个设计模式叫做组合模式,但容器构件和抽象构件之间是聚合关系,不要混淆啦。
11.2 组合模式实现
11.2.1 抽象构件类
它可以是接口或抽象类,为叶子构件和容器构件对象声明方法。
public abstract class Component {
public abstract void operation();
public void add(Component c) {
// 默认实现,抛出异常
}
public remove(Component c) {
// 默认实现,抛出异常
}
public Component getChild(int i) {
// 默认实现,抛出异常
return null;
}
}
11.2.2 叶子构件类
叶子构件没有子构件,它只实现了抽象构件中的 operation() 方法。
public class Leaf extends Component {
public void operation() {
// 叶子构件业务逻辑实现
}
}
11.2.3 容器构件类
容器构件包含子构件,其子构件可以是容器或叶子构件,它提供一个集合用于存储子构件。
public class Container extends Component {
private List<Component> list = new ArrayList<Component>();
public void add(Component c) {
list.add(c);
}
public void remove(Component c) {
list.remove(c);
}
public Component getChild(int i) {
return (Component)list.get(i);
}
public void operation() {
// 容器构件业务逻辑,递归执行,调用其中叶子节点的 operation 方法
for (Component c : list) {
c.operation();
}
}
}
11.3 透明组合模式
上述例子就是一个透明组合模式,叶子对象和容器对象所提供的方法是一致的,客户端可以完全同等的对待所有的对象。
但这种方式的缺点就是不够安全,因为叶子节点和容器节点是有本质上的区别的。叶子对象不会有子结构,不会包含成员对象,因此为其提供 add() 等方法是无意义的。
11.4 安全组合模式
安全组合模式结构图如下所示:
与透明组合模式相比,抽象构件 Component 中不再声明用于管理成员对象的方法,而是在容器构件 Container 中声明并实现。
安全组合模式的缺点就是不够透明,客户端无法同等对待叶子构件和容器构件。容器构件中那些管理成员对象的方法没有在抽象构件类定义,无法完全针对抽象类编程,必须区别的对待叶子构件和容器构件。
11.5 组合模式优/缺点
组合模式的应用例子:界面控件GUI
组合模式的优点主要如下:
- 新增容器构件和叶子构件都无须修改原有代码,符合开闭原则
- 客户端可以一致的使用容器构件和叶子构件,无须关系处理的单个对象还是容器对象,简化客户端代码
- 为树形结构的问题提供了一种灵活的解决方案,通过叶子对象和容器对象的递归组合可以形成复杂的树形结构,但对树形结构的操作却非常简单
组合模式的缺点主要如下:
- 很难对容器中的构件类型进行限制,因为所有的叶子构件都来自相同的抽象层,只能通过运行时进行类型检查来实现,这个过程较为复杂