组合模式是在处理树形结构时而经常使用的设计模式,树形结构一般是由很多节点对象组合而成的一个整体。我们在开发中经常会碰到这样的结构,比如二叉树、多叉树等,映射到真实生活场景中的书的目录结构,部门的层级结构或者是电脑中的文件目录结构等。
1. 概述
组合模式 是针对树形结构而发展出来的一种设计模式,树形结构是由节点对象组合而成的对象,呈现“个体-整体”的结构,这种模式可以使客户端在操作树形结构的整体或者个体节点对象时,能做出统一的响应,这种整体和个体的概念对客户端来说也是不可见的。
组合模式 可以很好的做到,复杂树形对象的层次结构与客户端解耦的目的,是一种结构性的设计模式。
在组合模式中,通常存在三个角色:
- 抽象构件:一般是接口或者抽象类,声明了子类的方法和属性。子类可以是一个叶子构件 ,也可以是一个容器构件。
- 叶子构件:实现了抽象构件的接口,位于树形结构中最末端的构件,不能包含其他组件,它需要实现了抽象构件所有的方法。
- 容器构件:实现了抽象构件的接口,表示容器节点对象,可以存放其他的容器构件对象或者叶子构件对象,在具体业务方法中可以通过递归的方式实现对子节点的遍历。
2. 代码实现
下面,我们通过一个电脑中文件目录树形结构的例子,来写一个组合模式的Demo案例,具体代码如下:
- 抽象构件
// 抽象的构件
public abstract class AbstractNode {// 节点名称protected String name;// 构造的文件名称AbstractNode(String name) {this.name = name;}// 添加节点的方法protected abstract void add(AbstractNode abstractNode);// 展示节点的方法protected void show(int lines) {StringBuilder sb = new StringBuilder("|");for (int i = 0; i < lines; i++) {sb.append("—— ");}sb.append(name);System.out.println(sb);}
}
- 叶子节点 - 文件
// 叶子节点 - 文件
public class File extends AbstractNode {// 构造函数File(String name) {super(name);}@Overrideprotected void add(AbstractNode abstractNode) {// 可以通过抛出异常表示子节点不支持的方法throw new RuntimeException("叶子构件不支持添加新的节点");}@Overrideprotected void show(int lines) {// 调用父类的方法super.show(lines);}
}
- 容器节点 - 文件夹
// 容器节点 - 文件夹
public class Folder extends AbstractNode{// 文件夹下面的子节点(包含容器节点和叶子节点)private List<AbstractNode> list;// 构造函数默认赋值public Folder(String name) {super(name);this.list = new ArrayList<>();}@Overrideprotected void add(AbstractNode abstractNode) {list.add(abstractNode);}@Overrideprotected void show(int lines) {// 先展示名称super.show(lines);// 节点展示 + 1lines ++;// 子节点的展示for (AbstractNode node : list) {node.show(lines);}}
}
- 客户端
// 客户端
public class Client {public static void main(String[] args) {// 定义文件夹AbstractNode folder = new Folder("D盘");folder.add(new File("日记.txt"));folder.add(new File("人民的名义.mp4"));// 添加子文件夹AbstractNode sonFolder1 = new Folder("音乐");sonFolder1.add(new File("周杰伦.mp3"));sonFolder1.add(new File("以父之名.mp3"));AbstractNode music = new Folder("张杰");music.add(new File("年轻的战场.mp3"));sonFolder1.add(music);AbstractNode sonFolder2 = new Folder("图片");sonFolder2.add(new File("快看这是美景图.jpeg"));folder.add(sonFolder1);folder.add(sonFolder2);// 文件展示folder.show(0);}
}
执行的结果如下展示:
3. UML类图
根据上面这个代码demo,我们来画一下对应的UML类图吧。
4. 模式分类
根据抽象构件中定义的方法,可以分为透明组合模式和安全组合模式两种
- 透明组合模式:在抽象构建中声明了所有管理成员的方法,包含增加、删除、获取、管理等方法,子类需要全部实现。
- 安全组合模式:在抽象构件中只定义关于操作的方法,由子类单独生命成员额增加、删除或者管理等方法。
5. 总结
我们来总结一下,组合模式的主要优点:
- 首先组合模式使得客户端可以统一使用组合的结构对象来处理叶子或者容器节点,而不必关系对象的特征,对调用方比较友好。
- 组合模式中添加新的容器构件和叶子构件都很方便,无需改动现有类结构,符合开闭原则。