一、什么是组合模式
将对象组合成树形结构以表示’部分-整体’的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
二、组合模式角色
1、Component (树形结构的节点抽象):为组合中的对象声明接口(公共属性,行为等的定义),实现所有类共有接口的默认行为, [可选]提供管理父节点对象的接口方法。
2、Leaf (树形结构的叶节点):在组合模式中表示叶子节点,叶子节点没有子节点。
3、Composite(树形结构的枝节点):定义枝节点行为,用来存储子部件,在Component接口中实现与子部件有关的操作,比如Add和Remove。
三、组合模式类图
四、组合模式代码
1、Component
public abstract class Component {
protected String name;
public Component(String name){
this.name = name;
}
public abstract void add(Component component);
public abstract void remove(Component component);
public abstract void display(int deep);
}
2、Leaf
public class Leaf extends Component {
public Leaf(String name) {
super(name);
}
@Override
public void add(Component component) {
System.out.println("叶子节点下不能添加节点!!!");
}
@Override
public void remove(Component component) {
System.out.println("叶子节点不能执行删除操作!!!");
}
@Override
public void display(int deep) {
StringBuilder sb = new StringBuilder();
for (int i = 0;i<deep;i++){
sb.append("-");
}
System.out.println(sb.append(this.name).toString());
}
}
3、Composite
public class Composite extends Component {
private List<Component> nodeList;
public Composite(String name) {
super(name);
nodeList = new ArrayList<>();
}
@Override
public void add(Component component) {
nodeList.add(component);
}
@Override
public void remove(Component component) {
nodeList.remove(component);
}
@Override
public void display(int deep) {
StringBuilder sb = new StringBuilder();
for (int i = 0;i<deep;i++){
sb.append("-");
}
System.out.println(sb.append(this.name).toString());
nodeList.forEach(n -> n.display(deep + 1));
}
}
4、客户端
public class MainClass {
public static void main(String[] args) {
Component root = new Composite("C:");
Component programFiles = new Composite("Program Files");
Component aTxt = new Leaf("a.txt");
root.add(programFiles); //添加文件夹
root.add(aTxt);
Component git = new Composite("Git");
Component bJava = new Leaf("b.java");
programFiles.add(git);
git.add(bJava);
root.display(0);
}
}
5、运行结果
五、透明方式和安全方式
我们上面实现的方式就是透明方式,在Component中声明了所有用来管理子对象的方法,其中包括add,remove。这样实现Component接口的所有子类都具备了add和remove方法。这样做的好处就是叶子节点和枝节点对于外界没有区别,它们具备完全一致的行为接口。但是因为Leaf类本身不具备add、remove方法的功能,所以实现它没有意义。
安全方式,就是在Component接口中不声明add和remove方法,Leaf就不用实现它,在Composite中声明所有用来管理子类的方法,不过由于不够透明,客户端调用需要做相应的判断,带来了不便。