前言
组合模式也称为整体部分模式,其结构比较简单,类似于组织结构的树状图,就像我所在的公司,属于集团下面的子公司,集团包括行政部门和财务,而我们公司也有这样两个部门,更加形象的说,组合模式最容易理解的是电脑的磁盘文件夹,文件夹里面可以有各类文件,也还可以有子文件夹,而子文件夹里面也同样可以有这些东西。关于定义则套用百度百科:组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。掌握组合模式的重点是要理解清楚 “部分/整体” 还有 ”单个对象“ 与 “组合对象” 的含义。
角色扮演
Component:抽象根节点,为组合模式中的对象声明接口,在适当情况可以实现类的接口,从而省掉接口类。声明一个接口用于访问和管理Component的子节点,可以再递归结构中定义一个接口,用于访问一个父节点,并在合适的时候实现这个接口。用简单的话来说,这个就是root根节点,然后子节点可以包含它,就像文件夹,子文件夹可以还有文件夹。
Composite:定义有子节点的那些枝干节点的行为,存储子节点,在Component接口中实现与子节点有关的操作。用文件夹举例:该对象就是一个子文件夹。
Leaf:在组合中表示叶子节点对象,叶子节点不在具有子节点,很好理解,这就相当于文件夹里面的各类文件。
适用场景
在表示对象的“部分-整体”结构时。
DEMO
因为一直拿文件夹举例,那我们就抽象一个文件夹的实例:
一个根目录下分为文件夹和普通文件,其都继承于File类,为了不违背依赖倒置原则,我们把文件夹的方法抽象到父类,由子类判断执行相关操作:
package com.demo.composite;
import java.util.ArrayList;
import java.util.List;
/**
* Created by italkbb on 2017/12/29.
*/
public abstract class File {
// 无论文件和文件夹都要名字
private String name;
// 存文件夹下所有元素
protected List<File> files = new ArrayList<>();
public File(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setName(String name){
this.name = name ;
}
/**
* 添加文件或者文件夹
* @param file
*/
public abstract void addFile(File file);
/**
* 删除文件或者文件夹
* @param file
*/
public abstract void removeFile(File file);
/**
* 输出文件结构
*/
public abstract void display();
/**
* 获取文件夹下所有文件和文件夹
* @return
*/
public abstract List<File> getFiles();
}
其次我们要写两个文件,文件夹对应Composite:
package com.demo.composite;
import java.util.List;
/**
* Created by italkbb on 2017/12/29.
*/
public class Folder extends File {
public Folder(String name) {
super(name);
}
@Override
public void addFile(File file) {
files.add(file);
}
@Override
public void removeFile(File file) {
files.remove(file);
}
@Override
public void display() {
System.out.print(getName() + "(");
for (File file:files){
System.out.print(file.getName() + ";");
if (file instanceof Folder){
file.display();
}
}
System.out.print(")");
}
@Override
public List<File> getFiles() {
return files;
}
}
以及普通文件,普通文件无权执行一些文件夹的操作,所以抛出异常,这个相当于Leaf:
package com.demo.composite;
import java.util.List;
/**
* Created by italkbb on 2017/12/29.
*/
public class NormalFile extends File {
public NormalFile(String name) {
super(name);
}
@Override
public void addFile(File file) {
throw new UnsupportedOperationException("普通文件不支持");
}
@Override
public void removeFile(File file) {
throw new UnsupportedOperationException("普通文件不支持");
}
@Override
public void display() {
System.out.print(getName());
}
@Override
public List<File> getFiles() {
throw new UnsupportedOperationException("普通文件不支持");
}
}
最后我们简单看一下使用的情况:
package com.demo.composite;
/**
* Created by italkbb on 2017/12/29.
*/
public class Client {
public static void main(String[] args){
// 创建根目录
File rootFile = new Folder("Root");
// 在根目录下创建几个文件和文件夹
rootFile.addFile(new NormalFile("README.md"));
rootFile.addFile(new NormalFile(".gitignore"));
rootFile.addFile(new NormalFile("build.gradle"));
File homeFile = new Folder("app");
homeFile.addFile(new NormalFile("Test.java"));
rootFile.addFile(homeFile);
}
}
后记
组合模式能够很清楚的定义分层次的复杂对象,使用的时候就可以忽略其层次结构,或者说弱化层次机构吧。组合模式使设计变得更加抽象,对象的业务规则如果很复杂,那么实现起来这个模式就变得很难,而且不是所有的方法都与叶子对象子类都有关联。