定义
? 用一个中介对象来封装一系列的对象交互. 中介者使得各对象不需要显式地相互引用, 从而使其耦合松散, 而且可以独立的改变它们之间的交互.
结构和说明
Mediator:?
中介者接口. 在里面定义各个同事之间交互需要的方法, 可以是公共的通讯方法, 比如 changed 方法, 大家都用, 也可以是小范围的交互方法.
ConcreteMediator:
? 具体中介者实现对象. 它需要了解并维护各个同事对象, 并负责具体的协调各同事对象的交互关系.
Colleague:
? 同事类的定义, 通常实现成为抽象类, 主要负责约束同事对象的类型, 并实现一些具体同事类之间的公共功能, 比如: 每个具体同事类都应该知道中介者对象, 也就是具体同事类都会持有中介者对象, 就可以定义到这个类里面.
ConcreteColleague:?
具体的同事类, 实现自己的业务, 在需要与其它同事通讯的时候, 就与持有的中介者通信, 中介者会负责与其它的同事交互.
体会中介者模式
如果没有主板? 如果电脑里面没有了主板, 那么各个配件之间就必须自行相互交互, 以互相传送数据, 理论上说, 基本上各个配件相互之间都存在交互数据的可能
有了主板, 各个配件的交互完全通过主板来完成, 每个配件都只需要和主板交互, 而主板知道如何和所有的配件打交道, 那就简单多了
存在的问题?
如果上面的情况发生在软件开发上呢??
如果把每个电脑配件都抽象成为一个类或者是子系统, 那就相当于出现了多个类之间相互交互, 而且交互还很繁琐, 导致每个类都必须知道所有需要交互的类, 也就是我们常说的类和类耦合了, 是不是很麻烦?
? 这样一来, 不但开发的时候每个类会复杂, 因为要兼顾其它的类, 更要命的是每个类在发生改动的时候, 需要通知所有相关的类一起修改, 因为接口或者是功能发生了变动, 使用它的地方都得变, 太可怕了吧! 那该如何来简化这种多个对象之间的交互呢?
案例:
使用电脑来看电影? 为了演示, 考虑一个稍微具体点的功能. 在日常生活中, 我们经常使用电脑来看电影, 把这个过程描述出来, 这里仅仅考虑正常的情况, 也就是有主板的情况, 简化后假定会有如下的交互过程:
1: 首先是光驱要读取光盘上的数据, 然后告诉主板, 它的状态改变了
2: 主板去得到光驱的数据, 把这些数据交给 CPU 进行分析处理
3:CPU 处理完后, 把数据分成了视频数据和音频数据, 通知主板, 它处理完了
4: 主板去得到 CPU 处理过后的数据, 分别把数据交给显卡和声卡, 去显示出视频和发出声音
? 当然这是一个持续的, 不断重复的过程, 从而形成不间断的视频和声音, 具体的运行过程不在讨论之列, 假设就有如上简单的交互关系就可以了. 也就是说想看电影, 把光盘放入光驱, 光驱开始读盘, 就可以看电影了
使用模式的解决方案
理解中介者模式
1: 中介者模式的功能?
中介者的功能非常简单, 就是封装对象之间的交互. 如果一个对象的操作会引起其它相关对象的变化, 或者是某个操作需要引起其它对象的后续或连带操作, 而这个对象又不希望自己来处理这些关系, 那么就可以找中介者, 把所有的麻烦扔给它, 只在需要的时候通知中介者, 其它的就让中介者去处理就可以了.
? 反过来, 其它的对象在操作的时候, 可能会引起这个对象的变化, 也可以这么做. 最后对象之间就完全分离了, 谁都不直接跟其它对象交互, 那么相互的关系, 全部被集中到中介者对象里面了, 所有的对象就只是跟中介者对象进行通信, 相互之间不再有联系.? 把所有对象之间的交互都封装在中介者当中, 无形中还得到另外一个好处, 就是能够集中的控制这些对象的交互关系, 这样有什么变化的时候, 修改起来就很方便.
2: 需要 Mediator 接口吗
? 有没有使用 Mediator 接口的必要, 取决于是否会提供多个不同的中介者实现. 如果中介者实现只有一个的话, 而且预计中也没有需要扩展的要求, 那么就可以不定义 Mediator 接口, 让各个同事对象直接使用中介者实现对象; 如果中介者实现不只一个, 或者预计中有扩展的要求, 那么就需要定义 Mediator 接口, 让各个同事对象来面向中介者接口编程, 而无需关心具体的中介者实现.
3: 同事关系?
在中介者模式中, 要求这些类都要继承相同的类, 也就是说, 这些对象从某个角度讲是同一个类型, 算是兄弟对象. 正是这些兄弟对象之间的交互关系很复杂, 才产生了把这些交互关系分离出去, 单独做成中介者对象, 这样一来, 这些兄弟对象就成了中介者对象眼里的同事.
4: 同事和中介者的关系?
中介者对象和同事对象之间是相互依赖的 .
5: 如何实现同事和中介者的通信?
一种实现方式是在 Mediator 接口中定义一个特殊的通知接口, 作为一个通用的方法, 让各个同事类来调用这个方法 . 另外一种实现方式是可以采用观察者模式, 把 Mediator 实现成为观察者, 而各个同事类实现成为 Subject, 这样同事类发生了改变, 会通知 Mediator.Mediator 在接到通知过后, 会与相应的同事对象进行交互.
6: 中介者模式的调用顺序示意图
广义中介者
标准的中介者模式在实际使用中的困难
1: 是否有必要为同事对象定义一个公共的父类??
大家都知道, Java 是单继承的, 为了使用中介者模式, 就让这些同事对象继承一个父类, 这是很不好的; 再说了, 这个父类目前也没有什么特别的公共功能, 也就是说继承它也得不到多少好处.? 在实际开发中, 很多相互交互的对象本身是没有公共父类的, 强行加上一个父类, 会让这些对象实现起来特别别扭.
2: 同事类有必要持有中介者对象吗?
? 同事类需要知道中介者对象, 以便当它们发生改变的时候, 能够通知中介者对象, 但是否需要作为属性, 并通过构造方法传入, 这么强的依赖关系呢?? 也可以有简单的方式去通知中介对象, 比如把中介对象做成单例, 直接在同事类的方法里面去调用中介者对象.
3: 是否需要中介者接口??
在实际开发中, 很常见的情况是不需要中介者接口的, 而且中介者对象也不需要创建很多个实例, 因为中介者是用来封装和处理同事对象的关系的, 它一般是没有状态需要维护的, 因此中介者通常可以实现成单例.
4: 中介者对象是否需要持有所有的同事??
虽说中介者对象需要知道所有的同事类, 这样中介者才能与它们交互. 但是是否需要做为属性这么强烈的依赖关系, 而且中介者对象在不同的关系维护上, 可能会需要不同的同事对象的实例, 因此可以在中介者处理的方法里面去创建, 或者获取, 或者从参数传入需要的同事对象.
5: 中介者对象只是提供一个公共的方法, 来接受同事对象的通知吗??
从示例就可以看出来, 在公共方法里, 还是要去区分到底是谁调过来, 这还是简单的, 还没有去区分到底是什么样的业务触发调用过来的, 因为不同的业务, 引起的与其它对象的交互是不一样的.? 因此在实际开发中, 通常会提供具体的业务通知方法, 这样就不用再去判断到底是什么对象, 具体是什么业务了.
对标准的中介者模式在实际使用中的改进
? 基于上面的考虑, 在实际应用开发中, 经常会简化中介者模式, 来使开发变得简单, 比如有如下的简化:
1: 通常会去掉同事对象的父类, 这样可以让任意的对象, 只要需要相互交互, 就可以成为同事;
2: 还有通常不定义 Mediator 接口, 把具体的中介者对象实现成为单例;
3: 另外一点就是同事对象不再持有中介者, 而是在需要的时候直接获取中介者对象并调用; 中介者也不再持有同事对象, 而是在具体处理方法里面去创建, 或者获取, 或者从参数传入需要的同事对象.? 把这样经过简化, 变形使用的情况称为广义中介者.
广义中介者示例 -- 部门与人员
1: 部门和人员的关系 : 是 多对多的
2: 问题的出现想想部门和人员的功能交互, 举几个常见的功能:
(1)部门被撤销 (2) 部门之间进行合并 (3) 人员离职 (4) 人员从一个部门调职到另外一个部门
想想要实现这些功能, 按照前面的设计, 该怎么做呢?
(1)系统运行期间, 部门被撤销了, 就意味着这个部门不存在了, 可是原来这个部门下所有的人员, 每个人员的所属部门中都有这个部门呢, 那么就需要先通知所有的人员, 把这个部门从它们的所属部门中去掉, 然后才可以清除这个部门.
(2)部门合并, 是合并成一个新的部门呢, 还是把一个部门并入到另一个部门? 如果是合并成一个新的部门, 那么需要把原有的两个部门撤销, 然后再新增一个部门; 如果是把一个部门合并到另一个部门里面, 那就是撤销掉一个部门, 然后把这个部门下的人员移动到这个部门. 不管是那种情况, 都面临着需要通知相应的人员进行更改这样的问题
(3)人员离职了, 反过来就需要通知他所属于的部门, 从部门的拥有人员的记录中去除掉这个人员.
(4)人员调职, 同样需要通知相关的部门, 先从原来的部门中去除掉, 然后再到新的部门中添加上.
看了上述的描述, 感觉如何?
麻烦的根源在什么地方呢? 仔细想想, 对了, 麻烦的根源就在于部门和人员之间的耦合, 这样导致操作人员的时候, 需要操作所有相关的部门, 而操作部门的时候又需要操作所有相关的人员, 使得部门和人员搅和在了一起.
3: 中介者来解决?
找到了根源就好办了, 采用中介者模式, 引入一个中介者对象来管理部门和人员之间的关系, 就能解决这些问题了.? 如果采用标准的中介者模式, 想想上面提出的那些问题点吧, 就知道实现起来会很别扭. 因此采用广义的中介者来解决, 这样部门和人员就完全解耦了, 也就是说部门不知道人员, 人员也不知道部门, 它们完全分开, 它们之间的关系就完全由中介者对象来管理了.
中介者模式的优缺点
1: 松散耦合
? 适当地使用中介者模式可以避免同事类之间的过度耦合, 使得各同事类之间可以相对独立地使用.
2: 集中控制交互
? 使用中介者模式可以将对象的行为和协作进行抽象, 能够比较灵活的处理对象间的相互作用.
3: 多对多变成一对多
? 使用中介者模式可以将对象间一对多的关联转变为一对一的关联, 使对象间的关系易于理解和维护.
4: 过度集中化
思考中介者模式
中介者模式的本质是: 封装交互
何时选用中介者模式
1: 如果一组对象之间的通信方式比较复杂, 导致相互依赖, 结构混乱, 可以采用中介者模式, 把这些对象相互的交互管理起来, 各个对象都只需要和中介者交互, 从而使得各个对象松散耦合, 结构也更清晰易懂
2: 如果一个对象引用很多的对象, 并直接跟这些对象交互, 导致难以复用该对象. 可以采用中介者模式, 把这个对象跟其它对象的交互封装到中介者对象里面, 这个对象就只需要和中介者对象交互就可以了
? 在面向对象编程中, 一个类必然会与其他的类发生依赖关系, 完全独立的类是没有意义的. 一个类同时依赖多个类的情况也相当普遍, 既然存在这样的情况, 说明, 一对多的依赖关系有它的合理性, 适当的使用中介者模式可以使原本凌乱的对象关系清晰, 但是如果滥用, 则可能会带来反的效果. 一般来说, 只有对于那种同事类之间是网状结构的关系, 才会考虑使用中介者模式. 可以将网状结构变为星状结构, 使同事类之间的关系变的清晰一些.
? 中介者模式是一种比较常用的模式, 也是一种比较容易被滥用的模式. 对于大多数的情况, 同事类之间的关系不会复杂到混乱不堪的网状结构, 因此, 大多数情况下, 将对象间的依赖关系封装的同事类内部就可以的, 没有必要非引入中介者模式. 滥用中介者模式, 只会让事情变的更复杂.
代码地址:
来源: http://www.bubuko.com/infodetail-3042721.html