介绍
中介者(Mediator)模式:定义一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互。中介者模式又叫调停模式,它是迪米特法则的典型应用。
在现实生活中,常常会出现好多对象之间存在复杂的交互关系,这种交互关系常常是“网状结构”,它要求每个对象都必须知道它需要交互的对象。例如,每个人必须记住他(她)所有朋友的电话;而且,朋友中如果有人的电话修改了,他(她)必须告诉其他所有的朋友修改,这叫作“牵一发而动全身”,非常复杂。
如果把这种“网状结构”改为“星形结构”的话,将大大降低它们之间的“耦合性”,这时只要找一个“中介者”就可以了。如前面所说的“每个人必须记住所有朋友电话”的问题,只要在网上建立一个每个朋友都可以访问的“通信录”就解决了。这样的例子还有很多,例如,你刚刚参力口工作想租房,可以找“房屋中介”;或者,自己刚刚到一个陌生城市找工作,可以找“人才交流中心”帮忙。
在软件的开发过程中,这样的例子也很多,例如,在 MVC 框架中,控制器(C)就是模型(M)和视图(V)的中介者;还有大家常用的 QQ 聊天程序的“中介者”是 QQ 服务器。所有这些,都可以采用“中介者模式”来实现,它将大大降低对象之间的耦合性,提高系统的灵活性。
优点
- 降低了对象之间的耦合性,使得对象易于独立地被复用。
- 将对象间的多对多关联转变为一对多的关联,提高系统的灵活性,使得系统易于维护和扩展。
缺点
- 当同事类太多时,中介者的职责将很大,它会变得复杂而庞大,以至于系统难以维护。
使用场景
当程序存在大量的类时,多个对象之间存在着依赖的关系,呈现出网状结构,那么程序的可读性和可维护性就变差了,并且修改一个类需要牵涉到其他类,不符合开闭原则。
因此我们可以引入中介者,将网状结构转化成星型结构,可以降低程序的复杂性,并且可以减少各个对象之间的耦合。
结构与实现
模式包含以下主要角色。
- Mediator(抽象中介者角色):抽象类或者接口,定义统一的接口,用于各同事角色之间的通信。
- ConcreteMediator(具体中介者角色):继承或者实现了抽象中介者,实现了父类定义的方法,协调各个具体同事进行通信。
- Colleague(抽象同事角色):抽象类或者接口,定义统一的接口,它只知道中介者而不知道其他同事对象。
- ConcreteColleague(具体同事角色):继承或者实现了抽象同事角色,每个具体同事类都知道自己本身的行为,其他的行为只能通过中介者去进行。
其结构图如下图所示。
中介者模式的实现代码如下:
程序的运行结果如下:
示例
我们的电脑组件异常之多,读取一个 CD 光盘需要使用 CPU 、光驱、声卡、显卡、内存等一系列组件。如果我们不使用设计模式,那我们每个组件都要保持其他组件的引用,这就会造成我们的类结构复杂难懂,变成一个网状结构。
解决方法:使用中介者模式可以使一系列组件只和我们的中介(主板)打交道,这就将网状结构变成星型结构。
每个对象只需要关心自己的职责,自己事情处理完成后通知中介者,让中介者调节指导下一步操作。
客户端代码:
ANDROID 源码中的实现
ANDROID 中的锁屏功能就用到了中介者模式,KeyguardService(锁屏服务)通过 KeyguardViewMediator(锁屏中介者)来协调各种 Manager 的状态以达到锁屏的功能。这里各种 Manager 都充当了同事的角色。源码如下:
KeyguardViewMediator 中通过 playSound 方法能够协调 AudioManager 去控制声音的播放等等,其他 Manager 同理。
实战
登录界面运用中介者模式,如下图所示。
一个简单的登录界面,包含两个文本框、两个复选框、两个按钮。只有 6 个元素,但要实现如下逻辑:
1)当用户名没有输入时,除了账户文本输入框、取消按钮外均不可用;当有用户名输入时,记住账号也可用。
2)当密码文本框有输入时,自动登录、确定按钮皆可用,否则皆不可用。
3)勾选自动登录,那么记住账号会被同时勾选。
4)清空密码,取消自动登录选中状态并且不可用;清空账号则取消两个复选框的状态并且都不可用。
5)……
这是一个多 UI 控件交互的情景,此时很适合让 Activity 来充当一个中介者并在其中处理相关逻辑。具体代码如下: