组合模式

对象的结构型模式

模式动机

考虑一个文件树遍历场景:

对于树形结构,当容器对象比如文件夹的某个方法被调用时,将遍历整个树形结构,寻找也包含这个方法的成员对象(可能还是容器比如子文件夹,也可能是叶子比如文件)并递归调用

由于容器对象和叶子对象在功能上的区别,客户端在使用它们时必须有区别地对待容器和叶子对象,但是我们希望客户端一致的处理它们,而不是添加复杂的条件控制语句。在这种需求下,组合模式应运而生。

组合模式描述了如何将容器对象和叶子对象进行递归组合,使得用户在使用时无须进行区分,可以一致地对待容器对象和叶子对象。

应用

组合模式组合多个对象形成树形结构以表示“整体-部分”的结构层次,对叶子对象和组合对象(即容器对象)的使用具有一致性。

组合模式包含如下角色:

  • 抽象构件Component
  • 叶子构件Leaf
  • 容器构件Composite
  • 客户类Client

关键是定义一个抽象构件类,使其既可以代表叶子也可以代表容器,从而让客户端可以面向抽象构件类编程,无需区分是叶子还是容器。

同时容器对象和抽象构件类之间还建立了聚合关系,代表容器之下亦有子节点,这个子节点既可以是容器也可以是叶子。(N叉树的结构)

典型抽象构件类代码如下:

public abstract class Component {
public abstract void add(Component c);
public abstract void remove(Component c);
public abstract Component getChild(int i);
public abstract void operation();
}

典型叶子构件类代码如下:

public class Leaf extends Component {
public void add(Component c){
//异常处理或错误提示
}
public void remove(Component c) {
//异常处理或错误提示
}
public Component getChild(int i) {
//异常处理或错误提示
}
public void operation() {
//实现代码
}
}

典型的容器构件类代码如下:

public class Composite extends Component {
private ArrayList list = new ArrayList();
public void add(Component c) {
list.add(c);
}
public void remove(Component c) {
list.remove(c);
}
public Component getChild(int i) {
(Component)list.get(i);
}
public void operation() {
for(Object obj:list) {
((Component)obj).operation();
}
}
}

实例:文件系统

实例:水果盘

水果盘中有水果,还有些更小的水果盘,现在需要吃水果,对于水果盘,吃就是吃里面的水果/果盘

实例:文件浏览

文件有不同类型,不同类型文件的浏览方式有所不同,比如文本文件和图片文件。文件系统中还有文件夹,对文件夹的浏览就是浏览其中的文件和子文件夹,现在希望客户端一致的操作不同类型文件和文件夹。

优点

  1. 清楚地定义分层次复杂对象,增加新构件也容易
  2. 客户端调用简单,可以一致地处理组合对象和单个对象
  3. 定义了类层次结构,叶子对象和容器对象都可以进一步递归地组合成容器对象,可以形成复杂的树形结构
  4. 更容易在组合体内加入对象构件,客户端不会因为加入新的构件而修改原来的代码,符合开闭原则

缺点

  1. 设计更加抽象,如果对象的业务规则很复杂,那其实很难实现组合模式,因为很难把不同的(叶子和容器)复杂对象的处理接口暴露成一模一样的,并且不是所有的方法都和叶子类有关联(比如容器的某个方法是容器特有的与叶子毫无关系)
  2. 很难对容器中的构建类型进行限制,因为都是抽象构件类

适用场合

  • 需要表示对象的整体或部分层次,且在这个整体-部分的层次结构中希望忽略整体与部分的差异,一致地处理它们
  • 客户希望忽略不同对象的层次差异,面向抽象构件编程,无需关心对象层次结构的细节
  • 对象的结构是动态变化的并且复杂程度不一样,但是客户需要一致地处理它们

示例:XML文件解析

XML文件是典型的层次结构,层次清晰

<?xml version="1.0"?>
<books>
<book>
<author>Carson</author>
<price format="dollar">31.95</price>
<pubdate>05/01/2001</pubdate>
</book>
<pubinfo>
<publisher>MSPress</publisher>
<state>WA</state>
</pubinfo>
</books>

模式扩展

带复杂继承的组合模式

透明组合模式

安全组合模式

(•‿•)