【程序员】看了这篇你将彻底了解组合模式( 五 )

super(name, position); }} Client类保存不变 , 运行结果也和上面一致 。
【程序员】看了这篇你将彻底了解组合模式
本文插图
模式讲解
上面使用的模式就是组合模式(Composite) , 组合模式的定义:将对象组合成树型结构以表示“部分-整体”的层次结构 。 组合模式使得用户对单个对象和组合对象的使用具有一致性 。
上面的管理者和员工就是部分和整体的关系 , 符合树状结构 。 组合模式的通用类图:
【程序员】看了这篇你将彻底了解组合模式
本文插图
Component:抽象的组件对象 , 定义组合对象的共有方法和属性 , 可以定义一些默认的行为或属性 。 这个抽象类既可以代表叶子对象 , 也可以代表组合对象 , 这样用户在操作的时候 , 对单个对象和组合对象的使用就具有了一致性 。
Leaf:叶子节点对象 , 定义和实现叶子对象的行为 , 不再包含其他子节点对象 。
Composite:组合对象 , 通常会存储子组件 , 定义包含子组件的那些行为 , 并实现在组件接口中定义的与子组件有关的操作 。
Client:客户端 , 通过组件接口来操作组合结构里的组件对象 。
组合模式的优点:
(1)统一了组合对象和叶子对象 , 局部和整体对于调用者来说没有区别 , 所有节点都是Component , 例如在上面示例中的通知方法中 ,for(Staff s:subordinateList)语句中的subordinateList列表中 , 肯定有组合对象也有叶子对象 , 即有管理者也有普通员工 , 我们不需要区分 , 都看作是Staff类型 。 有同学会说 , 骗谁呢 , 你这里没区分下面不还是判断了吗 , 下面改写一下 , 很简单 , 以getInfo为例 , 在抽象类中不写实现 , 在叶子子类中只输出自己的信息 , 在组合子类中也是先输出自己的信息 , 然后判断下属列表是否为空 , 不为空说明还有下属 , 然后再遍历下属对象并用下属去调用getInfo方法 , 递归输出每个对象信息 。
(2)节点自由添加 , 想添加一个组合节点或叶子节点只需要找到它的父节点就可以 , 非常容易扩展 , 符合开闭原则 。
组合模式的缺点:
与依赖倒置原则冲突 , 就是在客户端创建的时候直接使用了实现类 。
组合模式使用场景:
(1) 想要表示对象的部分与整体的层次结构 , 可以选择组合模式 , 把整体和部分的操作统一起来 , 使得层次结构实现更加简单 。
(2)如果想统一的使用组合结构中的所有对象 , 可以选用组合模式 。
【程序员】看了这篇你将彻底了解组合模式
本文插图
新的问题
细心的同学应该发现了 , 既然说组合模式是要让用户对叶子对象和组合对象的使用具有一致性 , 但是在创建对象的时候却还是使用各自的实现类创建的 , 这就涉及到组合模式实现的两种方式:安全性和透明性 。

  • 安全性:安全性指客户在使用的时候不会发送误操作 , 能访问的方法都是被支持的方法 。
  • 透明性:透明性指客户在使用的时候不需要区分组合对象还是叶子对象 。
简单来说 , 安全性的方式是将对组件的操作(如增加一个子组件 , 删除一个子组件 , 获取子组件)定义在组合类Composite中 , 这样叶子节点对象就不能使用这些功能(本身叶子对应就不应该有这些功能) , 就不会产生误操作的现象 。 上面的示例代码都是安全性方式的 。 但这会带来透明性的问题 , 客户在使用的时候必须区分到底使用的叶子对象还是组合对象 , 因为他们的功能是不同的 。
透明性方式是将对组件的操作定义在抽象类中 , 这样客户端只需面对Component , 不需要关系具体的组件类型 。 但这会带来安全性的问题 , 因为叶子对象也具有了操作组件的方法 , 客户就有可能误对叶子对象调用这些方法 , 这样的操作是不安全的 。 如上面的示例 , 用这种方式写就是普通员工也有发布通知的功能了 , 这显然是不允许的 。