一、组合模式概述
组合模式是用面向对象的方式来组合多个对象形成树形结构以表示“整体—部分”的结构层次,它对单个对象(叶子对象)和组合对象(容器对象)的操作具有一致性。其核心类是一个抽象类,通常这个类是整个模式中所有类的父类。下面是一个一般的文件目录树形结构图,组合模式就是用来操作管理类似的具有树形结构的对象组合的。
在组合模式中有叶子构件和容器构件两种构件,叶子构件中不能包含成员对象,而容器构件可以包含成员对象,就像上面的文件目录结构一样,文件夹相当于容器构件,文件相当于叶子构件,所以文件夹中即可以包含文件夹,也可以包含文件,而文件是最终的叶子构件,它不能再包含文件夹或文件。组合模式为叶子构件和容器构件提供了一个公共的抽象构件类,客户端可以针对该抽象类进行处理,而无须关心所操作的是哪种类型的对象。组合模式描述了如何将容器对象和叶子对象进行递归组合,使得用户在使用时无须对它们进行区别,可以一致地对待容器对象和叶子对象。
下图是一个典型的组合模式的结构图
从这个结构图上可以看到,组合模式主要包含以下角色:
1、Component(抽象构件):抽象构件为叶子构件和容器构件对象声明接口,在该角色中可以包含所有子类共有行为的声明和实现,在此构件中定义了访问及管理它的子构件的方法。2、Leaf(叶子构件):叶子构件没有子节点,它实现了在抽象构件中定义的行为。
3、Composite(容器构件):它表示容器节点对象,其子节点可以是叶子结点,也可以是容器节点,它提供了一个用于存储子节点的集合。
4、客户将通过抽象构件的接口访问和控制组合构件中的对象。
二、组合模式实例
文件有不同的类型,不同类型的文件的浏览方式是不同的,如对文件夹的浏览其实是对文件夹内所包含文件的浏览,而对具体文件的浏览则是对文件本身内容的浏览。下面用组合模式来模拟文件浏览的操作。为了便于描述问题,我只设计了一个简单的类图
下面是这个类图对应的代码
1. AbstractFile类,这是一个抽象类,即抽象构件类,它描述各种文件共有的操作方法
public abstract class AbstractFile {
public abstract void add(AbstractFile element);
public abstract void remove(AbstractFile element);
public abstract void display();
}
2. ImageFile类,叶子构件类,实现图像文件的相关操作
public class ImageFile extends AbstractFile {
@Override
public void add(AbstractFile elment) {
System.out.println(" An image file is added");
}
@Override
public void remove(AbstractFile element) {
System.out.println(" An image file is removed");
}
@Override
public void display() {
System.out.println(" An image file is displayed");
}
}
3. VideoFile类,叶子构件类,实现视频文件的相关操作
public class VideoFile extends AbstractFile {
@Override
public void add(AbstractFile elment) {
System.out.println(" An video file is added");
}
@Override
public void remove(AbstractFile element) {
System.out.println(" An video file is removed");
}
@Override
public void display() {
System.out.println(" An video file is displayed");
}
}
4. Folder类,容器构件类,实现文件夹的相关操作
public class Folder extends AbstractFile {
private ArrayList<AbstractFile> fileList = new ArrayList<AbstractFile>();
private String fileName;
Folder(String fileName)
{
this.fileName = fileName;
}
@Override
public void add(AbstractFile element) {
fileList.add(element);
}
@Override
public void remove(AbstractFile element) {
fileList.remove(element);
}
@Override
public void display() {
for(Object obj:fileList)
{
System.out.print(fileName);
((AbstractFile)obj).display();
}
}
}
5. Client类,客户端测试类
public class ClientTest {
public static void main(String argv[])
{
AbstractFile afile1, afile2, afile3, afile4, afile5;
Folder folder1, folder2, folder3;
afile1 = new ImageFile();
afile2 = new VideoFile();
folder1 = new Folder(" folder1 ");
folder1.add(afile1);
folder1.add(afile2);
afile3 = new ImageFile();
afile4 = new VideoFile();
folder2 = new Folder(" folder2 ");
folder2.add(afile3);
folder2.add(afile4);
afile5 = new VideoFile();
folder3 = new Folder("folder3\n");
folder3.add(folder1);
folder3.add(folder2);
folder3.add(afile5);
folder3.display();
System.out.println("\n--------------Remove folder1--------------\n");
folder3.remove(folder1);
folder3.display();
}
}
下面是客户端测试类在第一次调用display()函数前所构建出来的文件目录结构
三、小结
组合模式可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,使得增加新构件更容易;客户端可以一致地使用组合结构或其中单个对象,而不必关心自己处理的是单个对象还是整个组合结构;在组合体内加入新的对象构件很方便。但是组合模式使设计变得更加抽象,对象的业务规则如果很复杂,则实现组合模式是很困难的,而且不是所有的方法都与叶子对象子类有关联;增加新构件时很难对容器中的构件类型进行限制。