模式动机
在软件系统开发中,我们经常会遇到树形结构,比如我们操作系统中的文件系统,如下图:
文件夹里面可以放文件,也可以继续放文件夹,在组合模式中,对于这类对象我们称之为容器对象。文件是最小单元,不能再往里面放东西,对于这类对象我们称之为叶子对象。由于容器对象和叶子对象在功能上的区别,在使用这些对象的客户端代码中必须有区别地对待容器对象和叶子对象,而实际上大多数情况下客户端希望一致地处理它们,因为对于这些对象的区别对待将会使得程序非常复杂。那如何才能去掉容器对象和叶子对象的差异性,可以使得用户在使用时无须对它们进行区分,可以一致对待呢?此时,可以使用组合模式!
模式定义
组合多个对象形成树形结构以表示“整体-部分”的结构层次。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性。
模式结构
抽象构件:Component
叶子对象:Leaf
容器对象:Composite
代码示例
我们以开篇的文件系统为例,我们对文件夹进行遍历,如果是文件,则打印出文件名,如果是文件夹则继续遍历(递归调用)。我们用组合模式来实现这一功能。
//抽象构件,容器对象和叶子对象的抽象化
public abstract class Component {
public abstract void list();
}
import java.util.ArrayList;
//文件夹,也就是容器对象
public class Folder extends Component{
private ArrayList<Component> children = new ArrayList<Component>();
private String folderName;
public Folder(String folderName){
this.folderName = folderName;
}
public void add(Component c){
children.add(c);
}
@Override
public void list() {
System.out.println(folderName);
for(Component c:children){
c.list();
}
}
}
//文件,也就是叶子对象
public class File extends Component{
private String fileName;
public File(String fileName){
this.fileName = fileName;
}
@Override
public void list() {
System.out.println(fileName);
}
}
public class Client {
public static void main(String[] args) {
File file1 = new File("图片1");
File file2 = new File("图片2");
File file3 = new File("美女1");
File file4 = new File("美女2");
File file5 = new File("视频1");
File file6 = new File("视频2");
Folder folder1 = new Folder("图片文件夹");
Folder folder2 = new Folder("视频文件夹");
Folder folder3 = new Folder("美女图片");
Folder folder = new Folder("我的电脑");
folder1.add(file1);//把"图片1"放入"图片文件夹"中
folder1.add(file2);//把"图片2"放入"图片文件夹"中
folder3.add(file3);//把"美女1"放入"美女图片"中
folder3.add(file4);//把"美女2"放入"美女图片"中
folder1.add(folder3);//把"美女图片"文件夹放入"图片文件夹"中
folder2.add(file5);//把"视频1"放入"视频文件夹"中
folder2.add(file6);//把"视频2"放入"视频文件夹"中
folder.add(folder2);//把"图片文件夹"放入"我的电脑"中
folder.add(folder1);//把"视频文件夹"放入"我的电脑"中
folder.list();//遍历“我的电脑”
}
}
控制台输出
我的电脑
视频文件夹
视频1
视频2
图片文件夹
图片1
图片2
美女图片
美女1
美女2
总结
组合模式用于组合多个对象形成树形结构以表示“整体-部分”的结构层次。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性。组合模式的关键是定义了一个抽象构件类(Component),它既可以代表叶子,又可以代表容器,而客户端针对该抽象构件类进行编程,无须知道它到底表示的是叶子还是容器,可以对其进行统一处理。