组合模式
定义:将对象组合成树形结构,表示层次结构关系,并且让对象能够以同样的方式呈现给客户端程序。
在前面几篇介绍代理模式,桥接模式等模式的时候,我都会先举个实际场景,然后先介绍一种解决方案,接着指出这种方案的不足之处,最后再引出我们的xxx模式。但是我们接下来的组合模式就不采取这种讲解模式啦,因为它要解决的场景基本上没有其他的用来反衬的方案啦。
记住一点,凡是碰到有树形结构的关系的场景,基本上就用组合模式没跑啦。
我们操作系统中的文件夹结构,就是典型的树状结构
主要角色
- Component :组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理Component子部件。
- Leaf:叶子对象。叶子结点没有子结点。
- Composite:容器对象,定义有枝节点行为,用来存储子部件,在Component接口中实现与子部件有关操作,如增加(add)和删除(remove)等。
工作流程
既然我们提到组合模式是为了解决树状结构而生的,那么它究竟是如何解决的呢?由于我们的容器对象和叶子对象都实现了一个共同的Component接口,并都实现了接口里定义的一系列操作节点的方法,并且每个容器里有一个arrayList用来存储它的子节点(可以是叶子对象也可以是容器对象),当容器对象的指定方法被调用时,将遍历整个树形结构,寻找也包含这个方法的成员,并调用执行。其中,使用了递归调用的机制对整个结构进行处理。
如果前面解释的不是很清楚的话,接下来我们来看一个具体的实例,来模仿一个杀毒软件的设计
实例
让我们来梳理下一个杀毒软件是如何工作的,首先它肯定要对某个文件夹进行扫描,在该文件夹内,如果碰到图片、文本、视频文件等(即叶子对象),则直接对其处理,若是遇到子文件夹(容器对象),则对其递归处理...嗯,大致是这样的..是一个典型的树状结构
首先定义一个抽象构造,即Component接口
//抽象构建
public interface AbstractFile {
void killVirus(); //杀毒
}
接下来分别定义具体的图片、文本、视频的杀毒处理,即叶子对象,都要实现抽象构造接口
class ImageFile implements AbstractFile {
private String name;
public ImageFile(String name) {
super();
this.name = name;
}
@Override
public void killVirus() {
System.out.println("---图像文件:"+name+",进行查杀!");
}
}
class TextFile implements AbstractFile {
private String name;
public TextFile(String name) {
super();
this.name = name;
}
@Override
public void killVirus() {
System.out.println("---文本文件:"+name+",进行查杀!");
}
}
class VideoFile implements AbstractFile {
private String name;
public VideoFile(String name) {
super();
this.name = name;
}
@Override
public void killVirus() {
System.out.println("---视频文件:"+name+",进行查杀!");
}
}
接着再定义文件夹类,该类中增加add,remove方法以及一个用来存储子节点的arrayList对象。在杀毒方法中,对所有子节点进行遍历,然后调用每个节点的杀毒方法(递归形成)
class Folder implements AbstractFile {
private String name;
//定义容器,用来存放本容器构建下的子节点
private List<AbstractFile> list = new ArrayList<AbstractFile>();
public Folder(String name) {
super();
this.name = name;
}
public void add(AbstractFile file){
list.add(file);
}
public void remove(AbstractFile file){
list.remove(file);
}
public AbstractFile getChild(int index){
return list.get(index);
}
@Override
public void killVirus() {
System.out.println("---文件夹:"+name+",进行查杀");
for (AbstractFile file : list) {
file.killVirus();
}
}
}
客户端测试
public class Client {
public static void main(String[] args) {
AbstractFile f2,f3,f4,f5;
Folder f1 = new Folder("我的收藏");
f2 = new ImageFile("老高的大头像.jpg");
f3 = new TextFile("Hello.txt");
f1.add(f2);
f1.add(f3);
Folder f11 = new Folder("电影");
f4 = new VideoFile("笑傲江湖.avi");
f5 = new VideoFile("神雕侠侣.avi");
f11.add(f4);
f11.add(f5);
f1.add(f11);
// f2.killVirus();
f1.killVirus();
}
}
开发中的应用场景
凡是有树形结构的都可以用吧。。
- 操作系统的资源管理器
- GUI中的容器层次图
- XML文件解析
- OA系统中,组织结构的处理
- Junit单元测试框架