什么是组合模式
组合模式也叫合成模式,是将含有父子关系的一组单个对象,组合成用树结构表示的对象,也就是组合对象,可以表达出局部与整体的层次关系。
组合对象具有树结构的特性,所以,针对单个对象和组合对象的操作,就能抽象出统一的过程。
说白了,这也是树的自身特性,整体是树结构,局部也是树结构,能对树进行的操作,既适用于整体数据,也适用于局部数据。
通俗理解,组合模式就是实现对树结构的操作,要点有两个:
- 将具有父子关系的对象合成树结构,就是组合对象
- 用抽象、封装的编程思想实现对树结构的操作,适用于局部,也要适用于整体
设计与实现
提到树结构,就必须要注意树的几个节点类型:
- 树根结点:最顶层的节点,没有父节点,只有子节点
- 树枝节点:中间节点,有父节点,也有子节点
- 树叶节点:最底层节点,只有父节点,没有子节点
树结构在计算机中的应用,最典型的两个业务场景就是“文件目录”和“树型菜单”。
就拿文件目录举例子,看编程如何实现树结构的操作。
树根结点就是唯一的根目录,树枝节点就是中间的各级目录,树叶节点就是每级目录下的各个文件。
在下面的代码中,简化了实际场景中文件目录的功能及其表现,只提供构造树结构的方法,以及列举出目录及其子目录下所有文件的方法。
// 树节点的统一抽象
public abstract class TreeNode {
protected String name;
public TreeNode(String name) {
this.name = name;
}
}
// 树根节点(根目录)、树枝节点(一般目录)的统一抽象
public class Branch extends TreeNode {
private List<TreeNode> list = new ArrayList<>();
public Branch(String name) {
super(name);
}
public void add(TreeNode... nodes) {
for (TreeNode node : nodes) list.add(node);
}
public void fileList() {
fileList("");
}
private void fileList(String prefix) {
for (TreeNode treeNode : list) {
if (treeNode instanceof Branch) {
Branch branch = (Branch) treeNode;
branch.fileList(prefix + branch.name + "/");
} else {
System.out.println(prefix + treeNode.name);
}
}
}
}
// 树叶节点(文件)
public class Leaf extends TreeNode {
private String content;
public Leaf(String name, String content) {
super(name);
this.content = content;
}
}
这就是针对文件目录的组合模式代码实现,只实现了必要的属性方法,省略了很多不必要的代码。
提供一个简单的测试方法,Branch
对象的fileList()
方法既适用于整体的组合对象,也适用于局部的对象:
public static void main(String[] args) {
Branch root = new Branch("/");
Branch dir1 = new Branch("dir1");
Leaf dir1File1 = new Leaf("file1", "dir1 file1 content");
dir1.add(dir1File1);
Branch dir2 = new Branch("dir2");
Leaf dir2File1 = new Leaf("file1", "dir2 file1 content");
Leaf dir2File2 = new Leaf("file2", "dir2 file2 content");
dir2.add(dir2File1, dir2File2);
Branch dir3 = new Branch("dir3");
Leaf dir3File1 = new Leaf("file1", "dir3 file1 content");
Leaf dir3File2 = new Leaf("file2", "dir3 file2 content");
Leaf dir3File3 = new Leaf("file3", "dir3 file3 content");
dir3.add(dir3File1, dir3File2, dir3File3);
root.add(dir1, dir2, dir3);
System.out.println("------/目录及其子目录文件列表------");
root.fileList();
System.out.println("------dir1目录及其子目录文件列表------");
dir1.fileList();
System.out.println("------dir2目录及其子目录文件列表------");
dir2.fileList();
System.out.println("------dir3目录及其子目录文件列表------");
dir3.fileList();
}
组合模式的注意事项
可以说,组合模式就是树型结构的一种编程方法,如果应用场景很符合树结构的特征,那么,使用组合模式可以起到很好的作用。
但是,与此同时,树型结构的特征也在某种程度上限制了应用场景,如果应用场景在今后的变化中,脱离了树结构,或者不完全是树结构的表现,那么,组合模式就很难升级扩展。
综合而言,组合模式是个比较特殊的设计模式,与树型结构强相关,使用前,一定要多考虑当前以及今后的应用场景,是否真的契合树型结构条件。