中介者模式(Mediator)
调度、调停

意图

用一个中介对象(中介者)来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散
而且可以独立地改变它们之间的交互。
中介者模式又称为调停者模式。
面向对象的程序设计中,我们通常将功能进行分解,按照职责以类为维度进行划分,也就是使用时功能最终将分布在多个对象中
并且我们会尽可能的保持对象功能的单一(单一职责原则)
相对于对象的单一职责来说,任何的系统或者模块的功能却并不会单一,往往都是有多个对象交互协作来实现所有的功能
对象之间不可避免的需要建立连接
换句话说
系统(或者某模块)必然是复杂的(没有什么系统可以几个对象就轻松搞定,那样或许也不能称之为系统了吧)
功能必然会分布在多个对象中
多个对象协作必然需要联系必然导致耦合的产生

如上图所示,虽然系统对外呈现是一个统一的整体,但是,内部各个模块之间很可能是紧密的耦合 
各个模块相互联系,可能互相持有引用,会出现网状结构,完全不符合迪米特法则
如果对系统进行改动,将会变得困难

我们以装修为例
一般装修公司都会给每一个项目配备一个项目经理(这个项目也就是你家这个单子了,项目经理就是包工头)
装修的一般阶段分为:前期设计→拆改→水电→瓦工→木工→油漆→安装→保洁→软装
项目经理手上经常同时有几个工地在同步进行,只要错的开就好了
因为每个阶段都是有先后顺序的,你不可能先木工,然后再去拆改;
因为每个阶段也都需要一定时间,也意味着这一拨人不可能同时在你家工作
开工后项目经理会进行工作安排
水电工结束了A之后,项目经理会安排他到B,然后安排瓦工到A,然后........
所有的顺序都是由项目经理负责调度,水电工可以完全不认识瓦工,他们也完全不需要进行联系
有事儿找项目经理
如果没有项目经理,会是什么场景?
那就是人人都是项目经理,人人都需要管自己,还需要管别人
也就是每个人安排分配自己的时间与任务
水电工结束后需要联系瓦工进场,如果瓦工发现有遗留问题,需要联系水电工进行沟通
木工需要联系瓦工确认进展情况,油漆工又需要确认木工状况...
你会发现他们必须要经常保持联系,以获得进展情况,进而安排自己的工作
一个包工队尚且如此,如果是一个大的装修公司,怎么办?
而且装修而言,阶段之间还会有顺序,油漆工用不到联系水电工
但是在系统中,对象岂会仅仅与一个对象联系?
那岂不是更复杂、乱套?

中介者模式就是为了解决系统内部的调度问题,降低系统内部各模块之间的耦合度。
装修公司的项目经理、小组组长、班长,团队leader等其实这都是中介者模式的体现。

有很多书中以“房屋中介”作为中介者模式的一种场景
个人认为对于某一个房东或者租客而言,“房屋中介”的含义是为你服务的中介人员,此时的含义更接近代理模式
而从广义上看,有很多租客、买家,也存在很多房东,“房屋中介”将他们联系在一起,此时的“房租中介”应该是中介公司,这时才更符合中介者模式的含义
中介者模式的重点在于“调度、协调”,含义更接近“指挥中心”被指挥的是该系统内部的成员
如果在一个系统中对象之间存在多对多的相互关系
我们可以将对象之间的一些交互行为从各个对象中分离出来,并集中封装在一个中介者对象中,并由该中介者进行统一协调
如上图所示,对象之间多对多的复杂关系就转化为相对简单的一对多关系
简化了对象之间的复杂交互
显然,中介者模式是迪米特法则(不要和陌生人说话)的典型。  

结构

同事角色Colleague
系统中所有组成部件的抽象角色

具体的同事角色ConcreteColleague
系统的每一个具体的组成部分,就像公司的每个同事
提供自身职责功能的方法接口,供中介者调用
定义中介者到同事对象的接口,也就是提供接口给中介者调用
中介者(项目经理)根据你的技能分配任务,也就是调用你的方法
中介者角色Mediator
定义了同事Colleague对象到中介者的接口,也就是所有同事通信的接口(同事间的通信借助于中介者提供的这个方法)
也就是提供一个方法给同事们调用,用来请求其他同事协助协助,这个方法是中介者提供的
这个方法典型的示例就是事件处理方法

具体的中介者ConcreteMediator
具体的中介者,实现Mediator定义的接口,协调各同事进行协作

所有的成员之间,可以相互协调工作,但是却又不直接相互管理
这些对象都与项目经理“中介者”进行紧密联系
由项目经理进行工作协调,每个组成部分就如同我们项目组中的一个成员,也就是同事一样,这也是上文中Colleague 角色的由来
如何相互协调工作但是却又不直接相互管理?比如
class A{
void f(){
//do sth
B b = new B();
b.g();
}

上面伪代码中
类A有一个方法f ,做了一些事情之后,创建了一个B的对象b,然后调用b的方法g,做了一些处理
这就是A与B的协作,A也同时具有管理B的职责
如果转换为下面的形式,就是中介者模式
A和B的协作不在具有对象管理关系,而是项目经理Mediator统一进行管理 
class Mediator{
A a = new A();
B b = new B();
void cooperation(){
a.f();
b.g();
}
}

代码示例

使用《设计模式 可复用面向对象软件的基础》中的例子为原型
考虑一个图形用户界面中对话框的实现。
对话框使用一个窗口来展现一系列的窗口组件,比如按钮菜单输入域等

比如下图,IDEA的字体设置窗口,当进行Font字体设置时
  • 预览区域内的字体将会发生变化
  • 右下角的Apply 应用按钮将成为可点击状态

一种可能的解决方法
package mediator.simple;/**
* 设置字体类,提供字体设置方法.
* 并且创建展示Display对象,调用reDisplay方法重新展示
* 并且创建按钮Button对象,调用applyButton方法使能应用按钮
*/
public class Font {public void setFont() {System.out.println("设置字体...");Display display = new Display();display.reDisplay();Button button = new Button();button.applyButton();}
}

package mediator.simple;public class Display {public void reDisplay() {System.out.println("字体重新展示...");}
}

package mediator.simple;public class Button {public void applyButton() {System.out.println("应用按钮可用...");}
}

package mediator.simple;
public class Test {public static void main(String[] args) {Font font = new Font();font.setFont();}
} 

上面的示例很简单
为了实现“点击设置字体,选择字体后预览框字体的改变以及使能应用按钮的功能”
也就是联动的功能
设置字体后,分别创建展示和按钮对象,调用对象的方法
很显然,字体不仅操心自己的事情,还管理着展示Display和按钮Button
而且,如果直接点击取消会发生什么?一切将会还原,又伴随着一系列的调用
难道仍旧需要:“不仅操心自己的事情,还要负责管理别人么”?
就像没有项目经理的包工队一样了,既操心自己又要管理别人
成了我们上面所说的网状结构,内部各个同事之间的耦合度极高

重构中介者模式

重构的业务逻辑:
  • 通过引入mediator中介者,作为同事之间协作的中间人,提供operation()方法,用于同事间请求协助、事件处理
  • 每个同事类都知道这个中介,所以在抽象角色Colleague中设置了Mediator属性,构造方法注入,并且提供notifyEvent方法,封装了mediator的operation()方法
  • 当具体的同事ConcreteColleague,执行操作后,需要其他同事协作时,直接调用notifyEvent()方法
  • 每个具体的同事提供自身的职责接口
简单地说就是,提供中介者“项目经理”mediator,提供事件处理方法
所有的同事都只知道“项目经理”,如果有事需要其他同事办,就叫“项目经理”。

Mediator抽象中介者角色定义了operation方法
各个Colleague对象通过此方法进行通信,接受参数类型为Colleague的对象 
package mediator;
public abstract class Mediator {
abstract void operation(Colleague event);
}

Colleague抽象同事角色拥有Mediator,通过构造方法注入
提供了notifyEvent方法,调用中介者的operation方法,并且将自身作为参数
package mediator;
public abstract class Colleague {
private Mediator mediator;Colleague(Mediator mediator) {this.mediator = mediator;}public void notifyEvent() {mediator.operation(this);}
}

package mediator;
public class Button extends Colleague {Button(Mediator mediator){super(mediator);}public void applyButton() {System.out.println("应用按钮可用...");}
}

package mediator;public class Display extends Colleague {Display(Mediator mediator) {super(mediator);}public void reDisplay() {System.out.println("字体重新展示...");}
}

package mediator;public class Font extends Colleague {
private String fontName;public String getFontName() {return fontName;}Font(Mediator mediator) {super(mediator);}public void changeFont() {System.out.println("设置字体......");fontName = "微软雅黑";notifyEvent();}
}

ConcreteMediator实现了Mediator定义的接口
并且内部维护三个对象
如果事件类型是Font,那么调用设置字体的事件
package mediator;
public class ConcreteMediator extends Mediator {private Button button;private Display display;private Font font;ConcreteMediator() {button = new Button(this);display = new Display(this);font = new Font(this);}@Overridevoid operation(Colleague event) {if (event instanceof Font) {setFontEvent(event);}}private void setFontEvent(Colleague event) {System.out.println(((Font) event).getFontName());button.applyButton();display.reDisplay();}
}

测试代码
package mediator;public class Test {public static void main(String[] args){Mediator mediator = new ConcreteMediator();Font font = new Font(mediator);font.changeFont();}
}

上面的示例中,以设置字体为例,当字体变化时,请求“项目经理”安排其他同事协助
“项目经理”operation(Colleague event)  发现是设置字体的事件后,调用对应的事件处理方法,也就是寻找其他同事进行协助
中介者模式将每个场景中对象之间的协作进行封装  

小结

当你需要其他同事协助时,肯定不需要项目经理每次都创建具体的同事对象
上面的示例中,在ConcreteMediator的构造方法中创建的各个具体同事的实例(可以理解为项目经理手下有你和你的一帮同事)
你还可以提取出来工厂类用于管理同事类和中介者类
比如通过一个工厂对象管理各个同事实例(如果可以还可以将各个同事都设置为单例 )
并且中介者类作为这个工厂对象的内部类
同事对象的传递可以达到信息的获取与回调
通过给Font加了一个fontName属性,通过打印信息可以看得出来
通过将当时发生事件的对象传递了过来,可以获得事件的更多信息,可以根据信息进一步的进行操作
比如,此处的设置了字体,设置了什么字体?这一进一步的信息就通过参数携带进来
而且,这种方式还可以通知到Font本身
也就是可以在setFontEvent(Colleague event) 事件处理中,调用Font的方法进行结果返回,有回调的韵味
良好的扩展性
如果需要增加一个新的事件处理过程,比如点击取消按钮,还原字体设置,还原预览按钮
只需要在Button新增加一个职责(方法),然后在ConcreteMediator中新增加一种类型的事件处理程序即可
上面的示例中仅仅定义了几个简单的方法,实践中每个具体同事角色自然不会仅仅只有几个方法
不管有多少方法,都可以通过中介者将他们的协作逻辑进行封装
通过具体的中介者ConcreteMediator的处理方法进行安排
中介者模式可以很好地应用于事件通知的处理

中介者模式时序图

当某一个同事对象产生事件后,如果需要其他同事进行协助,他将调用中介者的方法
中介者接到消息后,调用其他同事的方法(安排其他同时干活),然后最终还可以将消息进行返回

与门面模式对比

门面模式和中介者模式都是通过中间类降低系统的耦合度
但是门面模式是为了子系统提供一个简单一致的接口,客户端透过门面类向子系统发送消息,可以认为消息的发送是单方向的
客户端--->门面--->子系统方法,子系统提供功能给客户端
门面是在外部客户端和内部子系统之间

中介者模式中,则是主要复杂系统内部多个对象之间的相互协作
中介者是各个内部对象同事之间  

扩展

任何模式都不是一成不变的,模式结构图只是一种相对比较合适准确的方案
但是涉及到具体的业务中,一切都是可变的
中介者模式也有多种灵活性
如果只有一个中介者对象,显然抽象Mediator角色是可以隐藏的
那么ConcreteMediator就兼顾了这个角色,提供通信接口给同事角色
中介者模式的本质含义是负责协调系统内部的多个交互的对象,将同事进行解耦
也就是说实现共同的接口并不是必须的
而实际上,一个系统中协作的多个对象,很可能是不同的类型,如果去掉了抽象角色Colleague
那么就可以将任意的有关联的对象组织在一起,通过中介者协同工作
而且,也并不意味着一定要中介者持有同事角色,如果合适,直接创建中介者也并非不可以
虽然上面提到你可以使用另外的工厂管理,那也只是一种常用用法而已。
只需要记住中介者的本质在于“行为与协作的分离,中介者封装了对象间的协作

总结

中介者模式将对象的行为和协作进行分离,使对象更加专注于对象的行为,也就是自身的功能
将协作分离出来封装到中介者内部
迪米特法则,不要和陌生人讲话,只与你的朋友通信,中介者模式是迪米特法则的典型应用
通过引入中介者对象,在同事之间的请求调用中,增加了“项目经理”,如果有事搞不定,需要协助,那么就找他 
每个人只和项目经理对话,也就是仅仅和项目经理这个朋友聊天,其他的同事都不理了    ̄□ ̄||
中介者将网状结构,转换为了星型结构
将多对多的关系,转换为了一对多的关系
所以中介者模式将系统中对象对其他对象的引用数目降到最低,简化了对象之间的交互
中介者模式将各个同事对象之间进行解耦,增加新的中介者或者同事都比较方便,符合开闭原则
MVC模式,也是一种典型的中介者模式,控制器负责视图层和模型层的调度处理,是一个明显的中介者。
中介者模式将同事进行解耦,但是各个Colleague类必须同中介者进行交互
更准确的说,解耦后的关系植入到了中介者自身,如果原来的同事对象间的相互调用非常复杂
那么,这个中介者也很可能非常的复杂难以维护
换言之,同事间的复杂性与耦合性转移到了中介者内部
中介者内部对于各个同事之间的协调代码不太可能复用,所以具体同事类的复用性也是以中介者的不可复用为代价的
如果系统中的各个对象之间存在复杂的引用关系,希望能够通过中间类将他们进行解耦
或者系统中对象间的引用混乱,交互太多,导致难以进行类的复用
你就可以考虑中介者模式
但是并不意味着任何涉及到多个类交互的地方都用中介者模式,如果原本并不复杂,使用中介者将会增加复杂度
基本前提就是紧密耦合,比如出现了网状结构
原文地址:中介者模式 调停者 Mediator 行为型 设计模式(二十一)

转载于:https://www.cnblogs.com/noteless/p/10130616.html

中介者模式 调停者 Mediator 行为型 设计模式(二十一)相关推荐

  1. 设计模式(十一)中介者模式(调停者模式)

    1. 中介者模式定义 定义:用一个中介者对象来封装一系列的对象交互.中介者使得各对象不需要显式地相互引用,从而使其松散耦合,而且可以独立地改变它们之间的交互. 中介者模式结构图如下图所示. 在中介者模 ...

  2. 观察者模式 Observer 发布订阅模式 源 监听 行为型 设计模式(二十三)

    观察者模式 Observer 意图 定义对象一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖他的对象都得到通知并自动更新. 别名:依赖(Dependents),发布订阅(Publish-Su ...

  3. java计数器策略模式_java设计模式(二十一)--策略模式

    对于策略模式,我在很多面试题上看到过考察这一类的问题,这种模式也的确比较好用. 我感觉这种模式就是将不同实现的方法放到一个接口中,然后通过实现这个接口来实现不同的运行结果,这种模式有三部分构成: 策略 ...

  4. 设计模式-行为型模式:中介者模式

    目录 1.简介 2.组成部分 3.优缺点 4.使用场景 5.代码实现 1.简介 中介者模式(Mediator Pattern)是一种行为型设计模式,它通过将对象间的交互行为集中到一个中介对象中,来降低 ...

  5. php中介模式,中介者模式(Mediator pattern)详解及PHP实现

    中介者模式是一种行为型模式,它包装了一系列对象相互作用的方式,使得这些对象不必相互明显作用,从而使它们可以松散偶合.当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用,保证这些作用可 ...

  6. 14.设计模式--中介者模式(Mediator模式)

    1.定义 中介者模式是一种行为型模式,是为了解决对象之间错综复杂的调用关系的一种设计模式,这种错综复杂的调用关系采用一个中介类来进行帮忙调用,所有的调用者只是需要关心中介者,而不需要进行互相依赖. 例 ...

  7. Android设计模式(十六)-中介者模式

    原文地址 http://blog.csdn.net/qq_25806863/article/details/69396448 中介者模式又叫调解者模式或调停者模式,是行为型设计模式之一. 生活中的中介 ...

  8. 设计模式(十四)中介者模式

    相关文章 设计模式(一)设计六大原则 设计模式(二)单例模式的七种写法 设计模式(三)建造者模式 设计模式(四)简单工厂模式 设计模式(五)观察者模式 设计模式(六)代理模式 设计模式(七)装饰模式 ...

  9. Python设计模式-中介者模式

    Python设计模式-中介者模式 代码基于3.5.2,代码如下; #coding:utf-8 #中介者模式class colleague():mediator = Nonedef __init__(s ...

最新文章

  1. nested exception is org.apache.ibatis.type.TypeException: Could not set parameters for mapping
  2. python day two,while
  3. pgpool-II的性能缺陷(二)
  4. Ubuntu16.04 配置pytorch
  5. python有趣的小项目-这10个Python项目超有趣!
  6. VB 宏+mysql解决EXCEL表格实现自动化处理
  7. 【手写】每个人心中都住着一座城。。。
  8. python的68个内置函数
  9. Spring Clould负载均衡重要组件:Ribbon中重要类的用法
  10. .Net(C#)用正则表达式清除HTML标签(包括script和style),保留纯本文(UEdit中编写的内容上传到数据库)...
  11. MR/hive/shark/sparkSQL
  12. [2007最后一博]Url地址重写,利用HttpHander手工编译页面并按需生成静态HTML文件...
  13. linux 调用外部变量,sed当中使用变量替换以及执行外部命令
  14. 计算机考试演示文稿模板,2018职称计算机考试PowerPoint习题10
  15. 【Java】OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes…… 的解决方法
  16. 面试被问线程池,真香
  17. vs2010跟vs2008比较增加了哪些功能
  18. 得到的概率值_手把手教你将矩阵概率画成图
  19. 前嗅ForeSpider教程:采集新浪新闻
  20. 从0到1搭建大数据平台之数据采集篇

热门文章

  1. c语言统计最长单词长度,求3个字符串中最长单词的长度 求救 会一个的
  2. java ase 加密_java实现ase加密解密
  3. yolo如何降低loss_从未看过如此通俗易懂的YOLO系列
  4. 开源Vue表格组件,表格插件源码
  5. [flite源码分析一]常用数据结构cst_val
  6. LeetCode 1114. Print in Order--Java解法--并发问题
  7. 华为鸿蒙概念机990,华为5G概念新机:鸿蒙OS系统+麒麟990+石墨烯 安卓机皇来势汹汹...
  8. ubuntu20安装mysql8.0.28
  9. 【每日一题】 面试题 17.14. 最小K个数
  10. Mybatis 3.5.X 解析LocalDateTime 错误问题