文章目录
详解Java设计模式之组合模式
案例引入
-
Windows的操作系统目录结构如下
-
分析
- 在树形目录结构中,包含文件和文件夹两类不同的元素
- 在文件家中可以继续包含子文件夹
- 在文件中不能在包含子文件(word中嵌入图片不是一个概念)
- 文件夹也叫作容器(Container)节点
- 文件也叫作叶子(Leaf)节点
- 当容器对象的某一个方法被调用时,将遍历整个属性结构,寻找包含这个方法的成员对象并调用执行,牵一而动百,其中使用了递归的机制来对整个结构进行处理
- 由于容器节点和叶子结点在功能上的区别,在使用这些对象的代码中必须有区别的对象容器节点和叶子节点,而实际上大多数情况下客户端希望一致的处理他们,因为对于这些对象的区别对待会导致程序较为复杂(就比如说需要进行不断的判定结构)
- 在树形目录结构中,包含文件和文件夹两类不同的元素
如何一致性的对待容器对象和叶子对象呢?????再比如一个大果盘里面装有小果盘和果子,小果盘里又装着小小果盘和果子,们想要吃到所有的水果的过程也是类似的。由此我们正式引出组合模式
组合模式
定义
组合模式:组合多个对象形成树形结构表示具有整体和部分关系的层次结构。组合模式让客户端可以统一的对待单个对象和组合对象。
Composite Pattern:Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and composition of objects uniformly.
- 组合模式属于对象结构性模式
- 又称为"部分-整体"模式
- 将对象组织到树形结构中,可以用来描述整体和部分的关系。
模式类图结构
相关角色
- Component 抽象构件
- Leaf 叶子构件
- Composite 容器构件
典型代码
-
抽象构件Component
-
public abstract class Component { public abstract void add(Component c); //增加成员 public abstract void remove(Component c); //删除成员 public abstract Component getChild(int i); //获取成员 public abstract void operation(); //业务方法 }
-
-
叶子构件 Leaf
-
public class Leaf extends Component { public void add(Component c) { //异常处理或错误提示 } public void remove(Component c) { //异常处理或错误提示 } public Component getChild(int i) { //异常处理或错误提示 return null; } public void operation() { //叶子构件具体业务方法的实现 }
-
-
容器构件
-
public class Composite extends Component { private ArrayList<Component> list = new ArrayList<Component>(); public void add(Component c) { list.add(c); } public void remove(Component c) { list.remove(c); } public Component getChild(int i) { return (Component)list.get(i); } public void operation() { //容器构件具体业务方法的实现,将递归调用成员构件的业务方法 for(Object obj:list) { ((Component)obj).operation(); } } }
-
案例分析
某软件公司欲开发一个杀毒(Antivirus)软件,该软件既可以对某个文件夹(Folder)杀毒,也可以对某个指定的文件(File)进行杀毒。该杀毒软件还可以根据各类文件的特点,为不同类型的文件提供不同的杀毒方式,例如图像文件(ImageFile)和文本文件(TextFile)的杀毒方式就有所差异。
现使用组合模式来设计该杀毒软件的整体框架。
类图设计
实例代码
(1) AbstractFile:抽象文件类,充当抽象构件类
(2) ImageFile:图像文件类,充当叶子构件类
(3) TextFile:文本文件类,充当叶子构件类
(4) VideoFile:视频文件类,充当叶子构件类
(5) Folder:文件夹类,充当容器构件类
(6) Client:客户端测试类
具体代码和更多相关实验可见我的gitee
https://gitee.com/plushuang/HelloWord/tree/master/src/csu/edu/cn/designpattern/compositepattern/example
结果分析
见代码
- 如果需要更换操作节点,例如只对文件夹“文本文件”进行杀毒,客户端代码只需修改一行即可
- 在具体实现时,可以创建图形化界面让用户来选择所需操作的根节点,无须修改源代码,符合开闭原则
JavaJDK中的组合模式
透明组合模式
其实也就是在抽象构件中提供add、remove、get等方法,但是这些方法叶子节点是不能使用的,只有容器节点能够使用。不够安全,一旦叶子节点调用需要进行报错或者提示处理,但是能够让客户端一致性的对待两者
安全组合模式
也就是抽象构件中不含上述三种方法,能够保证安全性,但是导致的就是不够透明,客户端不能完全的针对抽象编程。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6YQOsnst-1640067963922)(C:\Users\PlusHuang\AppData\Roaming\Typora\typora-user-images\image-20211221142113986.png)]
组合模式优点
- 可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,让客户端忽略了层次的差异,方便对整个层次结构进行控制
- 客户端可以一致地使用一个组合结构或其中单个对象,不必关心处理的是单个对象还是整个组合结构,简化了客户端代码
- 增加新的容器构件和叶子构件都很方便,符合开闭原则
- 为树形结构的面向对象实现提供了一种灵活的解决方案
组合模式缺点
- 在增加新构件时很难对容器中的构件类型进行限制
组合模式适用环境
- 在具有整体和部分的层次结构中,希望通过一种方式忽略整体与部分的差异,客户端可以一致地对待它们
- 在一个使用面向对象语言开发的系统中需要处理一个树形结构
- 在一个系统中能够分离出叶子对象和容器对象,而且它们的类型不固定,需要增加一些新的类型