描述
定义
将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。
类型
对象结构型模式
UML类图
实现
主要角色
- Component:抽象构件
- 为组合中的对象声明接口。
- 在适当的情况下,实现所有类共有接口的缺省行为。
- 声明一个接口用于访问和管理Component的子组件。
- (可选)在递归结构中定义一个接口,用于访问一个父部件,并在合适的情况下实现它。
- Leaf:树叶构件
- 在组合中表示叶节点对象,叶节点没有子节点。
- 在组合中定义图元对象的行为。
- Composite:树枝构件
- 定义有子部件的那些部件的行为。
- 存储子部件。
- 在Component接口中实现与子部件有关的操作。
- Client:客户端类
- 通过Component接口操纵组合部件的对象。
安全模式 VS 透明模式
组合模式的实现根据所实现接口的区别分为两种形式:安全模式和透明模式。安全模式要求管理子组件的方法只出现在树枝构件类中,而不出现在树叶构件中。而透明模式要求所有的具体构件类,不论树枝构件还是树叶构件,均符合同一个固定的接口。
对于组合模式而言,在安全性和透明性上,会更看重透明性,毕竟组合模式的目的是:让客户端不再区分操作的是树枝对象还是树叶对象,而是以一个统一的方式来操作。而且对于安全性的实现,需要区分的是树枝对象还是树叶对象。有时候,需要将对象进行类型强行转换,这种类型转换必然是不够安全的。
因此在使用组合模式的时候,建议多采用透明式的实现方式。
透明模式代码示例
-
Component:抽象构件
public abstract class Component { public void operation(); // 安全模式中下面接口方法只位于组合构件中 public abstract void add(Component component); public abstract void remove(Component component); public abstract List<Component> getChildren(); }
-
Leaf:树叶构件
public class Leaf extends Component { public void operation() { System.out.println("Leaf component"); } public void add(Component component) { throw new UnsupportedOperationException("对象不支持此功能"); } public void remove(Component component) { throw new UnsupportedOperationException("对象不支持此功能"); } // 空实现 public List<Component> getChildren() { return new ArrayList<Component>(); } }
-
Composite:树枝构件
public class Composite extends Component { // 构件容器 private ArrayList<Component> componentArrayList = new ArrayList<Component>(); public void add(Component component) { this.componentArrayList.add(component); } public void remove(Component component) { this.componentArrayList.remove(component); } public List<Component> getChildren() { return this.componentArrayList; } public operation() { for (Component c: componentArrayList) { c.operation(); } } }
-
Client:客户端类
public class Client { public static void main(String[] args) { Composite root = new Composite(); Leaf leaf = new Leaf(); leaf.operation(); root.add(leaf); root.operation(); } }
适用场景
- 需要表示对象的部分-整体层次结构。
- 希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
优点
- 简化了客户端代码。Composite模式采用树形结构来实现普遍存在的对象容器,从而将“一对多”的关系转化为“一对一”的关系,使得客户代码可以一致地处理对象和对象容器,无需关心处理的是单个的对象,还是组合的对象容器。
- 对树形结构的复杂对象容易控制。组合模式为树形结构的面向对象实现提供了一种灵活的解决方案,通过叶子对象和容器对象的递归组合,可以形成复杂的树形结构,但对树形结构的控制却非常简单。
- 增加新构件很方便。无须对现有类库进行任何修改,符合“开闭原则”。
缺点
- 使得设计更加复杂,客户端需要花更多时间理清类之间的层次关系。
- 在增加新构件时很难对容器中的构件类型进行限制。在需要检测组件类型时,不能依靠编译期的类型约束来实现,必须在运行期间动态检测。
相关模式
- 通常部件-父部件连接用于Responsibility of Chain模式。
- Decorator模式经常与Composite模式一起使用。当装饰和组合一起使用时,它们通常有一个公共的父类。因此装饰必须支持具有add、remove和getChildren操作的Component接口。
- Flyweight让你共享组件,但不再能引用他们的父部件。
- (迭代器模式)Itertor可用来遍历Composite。
- Visitor将本来应该分布在Composite和Leaf类中的操作和行为局部化。