组合模式是一种结构模式,他将对象组织到树的结构当中去。用来描述整体与局部的关系。
模式结构
组合模式包含3个角色:抽象构件、叶子构件、容器构件。
抽象构件可以使抽象类,也可以是接口。抽象构件为另两种构件对象的声明接口。其中包含有子类共有的方法。如:增加子构件、删除子构件、获取子构件等等。
叶子构件为叶子节点对象。叶子节点没有子节点,当调用叶子节点对象调用访问、管理子节点的方法时,可以采用抛出异常的方式处理。
容器构件为容器节点对象。容器节点对象中包含有叶子节点。它提供了一个集合用于存储叶子节点。
模式分类
组合模式分为透明组合模式和安全组合模式两种,区别如下:
透明组合模式:因为抽象模式中两个重要构件—容器构件和叶子构件都继承或实现抽象构件。那么如果抽象部件中拥有管理叶子构件的方法时,叶子构件应该是不包含这些方法的。由于采用继承或实现抽象构件,叶子构件会包含这些方法。所以我们必须设置,当叶子构件使用这些方法的时候,抛出异常等等的处理方法。这样做的优点是客户端程序无需分辨是叶子构件还是容器构件。但是违背了接口隔离原则。
安全组合模式:与透明组合模式相反,只在抽象构件中添加叶子构件和容器构件共有的方法。这样便可以解决透明组合模式。但是这样操作的话,当创建叶子节点对象时便不可以使用多态来创建。也就是说客户端程序必须分辨叶子构件和容器构件。这样会违背依赖倒置原则。
代码实现
例如,一个文件夹下面可以有图片、文本文件、视频文件。也可以包含文件夹。这种结构便可以使用组合模式。
抽象构件:
public abstract class AbstractFile {
abstract public void add(AbstractFile element);
abstract public void remove(AbstractFile element);
abstract public void display();
}
文件夹(容器构件)
import java.util.ArrayList;
public class Folder extends AbstractFile {
String fileName;
ArrayList<AbstractFile> fileList = new ArrayList<>();
Folder(String fileName){
this.fileName = fileName;
}
@Override
public void add(AbstractFile element) {
fileList.add(element);
System.out.println("element has been add");
}
@Override
public void remove(AbstractFile element) {
fileList.remove(element);
System.out.println("element has been removed");
}
@Override
public void display() {
for(AbstractFile i : fileList){
i.display();
}
}
}
图片文件(叶子构件)
public class ImageFile extends AbstractFile {
private String fileName;
ImageFile(String name){
this.fileName = name;
}
@Override
public void add(AbstractFile element) {
System.out.println("cant do it");
}
@Override
public void remove(AbstractFile element) {
System.out.println("cant do it");
}
@Override
public void display() {
System.out.println("name: " + fileName + " type: ImageFile");
}
}
视频文件(叶子构件)
public class VideoFile extends AbstractFile {
private String fileName;
VideoFile(String fileName){
this.fileName = fileName;
}
@Override
public void add(AbstractFile element) {
System.out.println("cant do it");
}
@Override
public void remove(AbstractFile element) {
System.out.println("cant do it");
}
@Override
public void display() {
System.out.println("name: " + fileName + " type: VideoFile");
}
}
文本文件(叶子构件)
public class TextFile extends AbstractFile {
private String filename;
TextFile(String filename){
this.filename = filename;
}
@Override
public void add(AbstractFile element) {
System.out.println("cant do it");
}
@Override
public void remove(AbstractFile element) {
System.out.println("cant do it");
}
@Override
public void display() {
System.out.println("name: " + filename + " type: TextFile");
}
}
客户端(测试类)
public class Client {
public static void main(String[] args) {
AbstractFile root = new Folder("root");
AbstractFile video = new VideoFile("video");
AbstractFile text = new TextFile("text");
AbstractFile image = new ImageFile("image");
root.add(video);
root.add(text);
root.add(image);
root.display();
System.out.println();
root.remove(video);
System.out.println();
root.display();
}
}
代码执行结果
name: video type: VideoFile
name: text type: TextFile
name: image type: ImageFile
element has been removed
name: text type: TextFile
name: image type: ImageFile