《设计模式》— 行为型模式 — 中介者模式
一、动机
面向对象设计鼓励将行为分布到各个对象中。这种分布可能会导致对象间有许多连接。在最坏情况下,每一个对象都知道其他所有对象。
虽然将一个系统分割成许多对象通常可以增强可复用性,但是对象间相互连接的激增又会降低其可复用性。大量的相互连接使得一个对象似乎不太可能在没有其他对象的支持下工作——系统表现为一个不可分割的整体。而且,对系统的行为进行任何较大的改动都十分困难,因为行为分布在许多对象中。这造成我们不得不定义很多子类以定制系统的行为。
例如,考虑一个图形用户界面中对话框的实现。对话框使用一个窗口来展现一系列的窗口组件,如按钮、菜单和输入域等,如下图所示:
对话框的窗口组件之间往往存在依赖关系。例如,在列表中选择某一个表项时,可能会改变某个输入域的内容;在输入域中输入文本可能会自动地选择一个或多个列表框中相应的表项;一旦文本出现在输入域中,其他一些按钮可能就变得能够使用了,这些按钮允许用户做一些操作,比如改变或删除文本所指的东西。
不同的对话框会有不同的窗口组件间的依赖关系。因此即使对话框显示相同类型的窗口组件,也不能简单地直接复用已有的窗口组件类,而必须定制它们以反映特定对话框的依赖关系。由于涉及多个类,用逐个生成子类的办法来定制它们会很冗长。
可以通过将集体行为封装在一个单独的中介者对象中来避免这个问题。中介者负责控制和协调一组对象间的交互。中介者充当一个中介以使组中的对象不再显式相互引用。这些对象仅知道中介者,从而减少了相互连接的数目。
例如,FontDialogDirector 可作为一个对话框中的窗口组件间的中介者。FontDialogDirector 对象知道对话框中的各窗口组件,并协调它们之间的交互。它充当窗口组件间通信的中转中心:
各对象之间的交互如图:
不难发现,这里的具体窗口类都并不依赖于具体的中介者,而是依赖于抽象的 DialogDirector。而具体的窗口类由于负责具体窗体对象间的通信,因此持有具体窗口类而非抽象类的引用。这里,中介者起到的就是调度的作用。
二、适用性
- 一组对象以定义良好但复杂的方式进行通信,产生的相互依赖关系结构混乱且难以理解。
- 一个对象引用其他很多对象并且直接与这些对象通信,导致难以复用该对象。
- 想定制一个分布在多个类中的行为,而又不想生成太多的子类。
三、结构
典型的对象结构为:
四、参与者
1、Mediator
- 终结者定一个接口用于与各同事对象通信,
2、ConcreteMediator
- 具体中介者通过协调各同事对象实现协作行为。
- 了解并维护它的各个同事。
3、Colleague class
- 每一个同事类都知道它的中介者对象。
- 每一个同事对象在需要与其他同事通信的时候,与它的中介者通信。
五、效果
1、减少了子类的生成
Mediator 将原本分布于各个对象间的行为集中在一起。改变这些行为只需生成 Mediator 的子类即可,这样各个 Colleague 类可被复用。
2、将各 Colleague 解耦
Mediator 有利于各 Colleague 间的松耦合,你可以独立地改变和复用各 Colleague 类和 Mediator 类。
3、简化了对象协议
用 Mediator 和各 Colleague 间的一对多交互来代替多对多交互。一对多的关系更容易理解和维护。
4、对对象如何协作进行了抽象
将中介作为一个独立的概念并将其封装在一个对象中,使你将注意力从对象各自本身的行为转移到它们之间的交互上来。和有助于弄清楚一个系统中的对象是如何交互的。
5、使控制集中化
中介者模式将交互的复杂性变为中介者的复杂性。因为中介者封装了协议,它可能变得比任何一个 Colleague 都复杂。这可能使得中介者自身成为一个难于维护的庞然大物。
六、实现
1、忽略抽象的 Mediator 类
当各 Colleague 仅与一个 Mediator 一起工作时,没有必要定义一个抽象的 Mediator 类。Mediator 类提供的抽象耦合已经使各 Colleague 可与不同的 Mediator子类一起工作,反之亦然。
2、Colleague-Mediator 通信
当一个感兴趣的事件发生时,Colleague 必须与其 Mediator 通信。一种方法是使用观察者模式,将 Mediator 实现为观察者,将 Mediator 作为 Subject,一旦其状态改变就发送通知给 Mediator。Mediator 做出的响应是将状态改变的结果传播给其他的 Colleague。