定义与特点
- 定义
又叫作部分-整体模式,它是一种将对象组合成树状的层次结构的模式,用来表示“部分-整体”的关系,使用户对单个对象和组合对象具有一致的访问性。
组合模式实现的最关键的地方是——简单对象和复合对象必须实现相同的接口。这就是组合模式能够将组合对象和简单对象进行一致处理的原因。
参与角色
- 抽象构件(Component)角色:为树叶构件和树枝构件声明公共接口,并实现它们的默认行为。
- 树叶构件(Leaf)角色:是组合中的叶节点对象,它没有子节点,实现抽象构件角色中声明的公共接口。
- 树枝构件(Composite)角色:是组合中的分支节点对象,它有子节点。定义有枝节点的行为,用来存储子部件,实现了抽象构件中的有关操作,如增加(add)和删除(remove)、获取子节点(getChild)等
结构代码分析
组合模式分为透明式的组合模式和安全式的组合模式。
- 透明组合模式(推荐使用)
在抽象构件中声明了所有来管理子对象的方法,其中包括add,remove等。这样实现抽象构件接口的所有子类都具备了add和remove方法。这样做的好处是叶节点和枝节点对于外界没有区别,它们具备完全一致的接口。
弊端:客户端对叶节点和枝节点是一致的,但叶节点并不具备add和remove的功能,因而对它们的实现是没有意义的,叶节点可通过抛出异常的方式来解决非法调用。
- 安全组合模式
在抽象构件中不去声明add和remove方法,那么子类的Leaf就不需要实现它,而是在树枝构件中去声明所有用来管理子类对象的方法。
弊端:叶节点无需在实现add与remove这样的方法,但是对于客户端来说,必须对叶节点和枝节点进行判定,为客户端的使用带来不便。
结构代码
这里以透明模式为例,实现集合 c0={leaf1,{leaf2,leaf3}}元素的访问,对应的树结构图如下:
声明抽象构件
interface Component { public void add(Component c); public void remove(Component c); public Component getChild(int i); public void view(); }
声明树叶构件
class Leaf implements Component { private String name; public Leaf(String name) { this.name = name; } public void add(Component c) {} public void remove(Component c) {} public Component getChild(int i) { return null; } public void view() { System.out.println("树叶" + name + ":被访问!"); } }
声明树枝构件
class Composite implements Component { private ArrayList<Component> children = new ArrayList<Component>(); public void add(Component c) { children.add(c); } public void remove(Component c) { children.remove(c); } public Component getChild(int i) { return children.get(i); } public void view() { for (Object obj : children) { ((Component) obj).view(); } } }
测试程序调用
public class ComponentTest { public static void main(String[] args) { Component c0 = new Composite(); Component c1 = new Composite(); Component leaf1 = new Leaf("1"); Component leaf2 = new Leaf("2"); Component leaf3 = new Leaf("3"); c0.add(leaf1); c0.add(c1); c1.add(leaf2); c1.add(leaf3); c0.view(); } }
总结
优点
- 可详细的定义分层次的复杂对象,用户可以忽略层次的差异。
- 基本对象可以被组合成复杂组合对象,这个组合对象也可以被组合,这样不断递归,客户端调用基本对象的地方都可以使用组合对象。
- 方便将新的叶子构件放入容器构件中。
- 缺点
层次关系的出现使得设计复杂。(所有设计模式共有的问题)
适用场景
- 当想表达对象的部分-整体的层次结构时
- 希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象时