组合模式(Composite Pattern)
组合模式分两种:
一、安全形式的组合模式
如果把管理子组件的操作定义在Composite中,那么客户在使用叶子对象的时候,就不会发生使用添加子组件或是删除子组件的操作了,因为压根就没有这样的功能,这种实现方式是安全的。但是这样一来,客户端在使用的时候,就必须区分到底使用的是Composite对象,还是叶子对象,不同对象的功能是不一样的。也就是说,这种实现方式,对客户而言就不是透明的了。
安全式组合模式
二、透明形式的组合模式
如果把管理子组件的操作定义在Component中,那么客户端只需要面对Component,而无需关心具体的组件类型,这种实现方式就是透明性的实现。事实上,前面示例的实现方式都是这种实现方式。但是透明性的实现是以安全性为代价的,因为在Component中定义的一些方法,对于叶子对象来说是没有意义的,比如:增加、删除子组件对象。而客户不知道这些区别,对客户是透明的,因此客户可能会对叶子对象调用这种增加或删除子组件的方法,这样的操作是不安全的。
组合模式的透明性实现,通常的方式是:在Component中声明管理子组件的操作,并在Component中为这些方法提供缺省的实现,如果是有子对象不支持的功能,缺省的实现可以是抛出一个例外,来表示不支持这个功能。
透明式组合模式
两种组合模式的共同构成:
1、Component:组合模式的对象接口声明,用于访问和管理其子组件。
2、Leaf:表示叶子节点对象,叶子节点无子节点,并实现了Component的所有方法
3、Composite:组合部件含有子部件,并实现了操作子部件的所有方法,实现了Component的所有方法
组合模式的应用举例:
最常见的组合模式应用就是文件系统,文件系统是树形结构。当我们对单个文件进行如复制、剪切和删除等操作时和对某个文件夹做同类操作时感觉是一样的,都像是在操作某个文件。现在我们来简单模拟一下复制操作,采用安全模式的代码如下:
//组合模式的公共接口 用于声明一些通用操作
public interface Component {
void copy();
}
//组合模式的leaf
public class File implements Component {
private String filename;
public File(String filename) {
this.filename = filename;
}
@Override
public void copy() {
System.out.println("复制文件" + filename);
}
}
import java.util.ArrayList;
//组合模式的composite
public class Folder implements Component {
private ArrayList<Component> comList;
private String folderName;
public Folder(String folderName) {
this.comList = new ArrayList<Component>(0);
this.folderName = folderName;
}
public void add(Component com){
comList.add(com);
}
public void remove(Component com){
comList.remove(com);
}
@Override
public void copy() {
System.out.println("复制文件夹:" + folderName);
for(Component c:comList){
c.copy();
}
}
}
//客户类 用于测试
public class Client {
public static void main(String[] args) {
//创建文件夹
Folder folder = new Folder("资料文件夹");
Folder bookFolder = new Folder("书籍文件夹");
Folder filmFolder = new Folder("影音文件夹");
//创建文件
File book1 = new File("设计模式。pdf");
File book2 = new File("简爱。txt");
File film1 = new File("第四区。avi");
File film2 = new File("功夫。avi");
//将filmFolder和bookFolder文件放到folder文件夹下
folder.add(filmFolder);
folder.add(bookFolder);
//将film1和film1文件放到filmFolder文件夹下
filmFolder.add(film1);
filmFolder.add(film2);
//将book1和book2文件放到bookFolder文件夹下
filmFolder.add(book1);
filmFolder.add(book2);
//复制文设计模式。pdf
System.out.println("------------------复制文设计模式。pdf操作------------------");
book1.copy();
//复制资料文件夹
System.out.println("--------------------复制资料文件夹操作--------------------");
folder.copy();
}
}
运行结果:
优点:
1、定义了包括基本对象和组合组合对象的层次结构,基本对象可以被组合成更复杂的对象,而且这个对象还可以被组合。
2、简化了客户代码。
3、使得更容易增加新类型的组件。
4、使设计变得更变通。
1、需要表示对象的“部分-整体”的层次关系。2、需求是用户对单个对象和组合对象的使用具有一致性