一.定义
组合模式也叫整体-部分模式,目的是为了实现整体和部分都有一组相同的操作方法。
属于结构型模式
注意区别一下组合和聚合的区别:
组合:各部分组织结构有相同的生命周期,例如人的各个器官和人,人死了器官也就消亡了;文件夹删了里面的文件也没了
聚合:各部分组织结构不具有相同生命周期,一个离开了另一个还能存活,例如桌子和电脑
二.实现
1.组件
抽象组件:一般是一个接口或者抽象类,定义通用的行为
具体组件:实现抽象组件的方法,定制自己的行为
2.通用写法
举一个文件目录的例子吧
定义一个抽象组件Directory,他具有rename,getName通用方法,子类可以实现也可以不实现,还有show抽象方法,由具体的子类去实现。
public abstract class Directory {
protected String name;
public Directory(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void rename(Directory directory, String newName) {
System.out.println(directory.getName() + "重命名为 --> " + newName);
}
abstract void show();
}
定义一个具体组件,目录类Folder,它实现了父类Directory的show方法,并且自定义了一些自己的方法addChild和removeChild
public class Folder extends Directory{
/**
* 层级
*/
private Integer level;
private List<Directory> directoryList = new LinkedList<Directory>();
public Folder(String name, Integer level) {
super(name);
this.level = level;
}
/**
* 新增子节点
* @param directory
*/
public void addChild(Directory directory) {
this.directoryList.add(directory);
}
/**
* 删除子节点
* @param directory
*/
public void removeChild(Directory directory) {
this.directoryList.remove(directory);
}
/**
* 打印信息
*/
@Override
public void show() {
System.out.println(this.name);
for (Directory directory : directoryList) {
if (this.level != null) {
for (Integer i = 0; i < this.level; i++) {
System.out.print(" ");
}
for (Integer i = 0; i < this.level; i++) {
if (i == 0) {
System.out.print("+");
}
System.out.print("-");
}
}
directory.show();
}
}
}
创建一个具体的组件File类,继承Directory,实现了show方法
public class File extends Directory {
public File(String name) {
super(name);
}
@Override
public void show() {
System.out.println(this.name);
}
}
客户端测试类:
public class Test {
public static void main(String[] args) {
Folder folder1 = new Folder("office", 2);
File ppt = new File("ppt");
File excel = new File("excel");
File word = new File("word");
folder1.addChild(ppt);
folder1.addChild(excel);
folder1.addChild(word);
Folder folder2 = new Folder("entertainment", 2);
File qq = new File("qq");
File wx = new File("wechat");
folder2.addChild(qq);
folder2.addChild(wx);
Folder root = new Folder("d:", 1);
root.addChild(folder1);
root.addChild(folder2);
root.show();
}
}
输出
上面的例子中,File和Folder都有一个共同的方法rename,同时也对show方法进行了不同的实现,Folder还定义了自己的addChild和removeChild方法,这种抽象组件不声明全部的方法子类在需要时进行定制的方法属于安全模式的组合模式。除了安全模式的组合模式外,还有透明模式的组合模式,就是抽象组件定义全部的方法,子类可以覆盖或者不覆盖,这种方式违背了迪米特法则。
那么什么时候用安全模式的什么时候用透明模式呢?
安全模式:子类要实现的方法大部分都不相同时
透明模式:子类要实现的方法大部分都相同时
三.组合模式在源码中的应用
HashMap、ArrayList、SqlNode
四.组合模式的优缺点
优点:符合开闭原则,忽略了层次的差异,方便对整个层次结构进行控制
缺点:抽象行为设计比较复杂