初探中介者模式

代码链接

koonchen/design-patterns/mediator

要点

用一个中介对象来封装一系列的对象交互。中介者使兑现不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

面向对象设计鼓励将行为分布到各个对象中,这种分布可能会造成许多连接,最坏的情况下,每个对象都知道其他所有对象。

大量的相互连接使得一个对象那个不能在没有其他对象的支持下工作——系统表现为一个不可分割的对象。我们不得不定义很多子类以定制系统的行为。

可以通过将集体行为封装在一个单独的中介者对象中来避免这个问题,中介者负责控制和协调一组对象间的交互。中介者充当一个中介使得组中的对象不再相互显式引用,这些对象仅知道中介者,从而减少了相互连接的数目。

下面我们用 FontDialogDirector 来作为一个对话框组件间的中介者。

cover

下面的交互图说明了各对象如何协作处理一个列表框中选项的变化。

cover

  1. 列表框告诉它的操作者它被改变了。
  2. 导控者从列表框中得到选中的选择项。
  3. 导控者将选择项传递给入口域。
  4. 现在入口域中已有正文,导控者使得用于发起一个动作的某个按钮可用。

导控者是如何在对话框和入口域之间进行中介中。窗口组件之间的通信都是通过导控者间接地进行。它们不必互相知道,它们仅需要知道导控者。所以只要扩展或替换这个类,就可以改变和替换这些行为。

下面是 FontDialogDirector 抽象被集成到一个类库中:

cover

中介者模式的适用性:

  • 一组对象以定义良好但是复杂的方式进行通信。
  • 一个对象引用其他很多对象并且直接与这些对象通信,导致难以复用该对象。
  • 想定制一个分布在很多类中的行为,而又不想生成太多的子类。

中介者模式的参与者:

Mediator — 中介者定义一个接口用于与各同事对象通信。

ConcreteMediator — 具体中介者通过协调各同事对象实现协作行为。

Colleague Class — 每一个同事类都知道它的中介者对象。

中介者模式的结构:

cover

协作的过程中,同事向一个中介者对象发送和接收请求,中介者在各同事间适当地转发请求以实现协作行为。

中介者模式有以下优点与缺点:

  • 减少了子类的生成:它将原本分布于多个对象间的行为集中在一起,改变这些行为只需生成中介者的子类即可。
  • 它将各 Colleague 解耦:我们可以独立改变和复用各 Colleague 类和 Mediator 类。
  • 它简化了对象协议:用 Mediator 和各 Colleague 间的一对多的交互来代替多对多的交互。
  • 它对对象如何协作进行了抽象:将中介作为一个独立的概念并将其封装在一个对象中,使你讲注意力从对象各自本身的行为转移到它们之间的交互上来。
  • 它使控制集中化:中介者模式将交互的复杂性变为中介者的复杂性。这可能使得中介者自身成为一个难于维护的庞然大物。

实现

实现过程中有以下需要考虑的问题:

  • 忽略抽象的 Mediator 类:当各 Colleague 仅与一个 Mediator 一起工作,没有必要定义一个抽象的 Mediator 类。
  • Colleague — Mediator 通信:当一个感兴趣的事件发生的时候,Colleague 必须与其 Mediator 通信。

Java 实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// 改变的组件
class Colleague {
Mediator mediator;

public void setMediator(Mediator mediator) {
this.mediator = mediator;
}

public void changed() {
mediator.widgetChanged(this);
}

public void doSth(){}
}

class ConcreateColleague extends Colleague {
ConcreateColleague colleague;
public void doSth() {
System.out.println("ConcreateColleague instance has been created");
}
}

// 中介者
class Mediator {
public void showDialog() {}
public void createWidgets() {}
public void widgetChanged(Colleague colleague) {}
}

class ConcreteMediator extends Mediator {
@Override
public void widgetChanged(Colleague colleague) {
colleague.doSth();
}
}

public class MediatorClient {
public static void main(String[] args) {
Colleague colleague = new ConcreateColleague();
Mediator mediator = new ConcreteMediator();
mediator.widgetChanged(colleague);
}
}

相关模式:

  • Facade 模式与中介者欧氏的不同之处在于 Facade 是对一个子系统进行抽象,从而提供了一个更为方便的接口,它的协议是单向的,即 Facade 对象对这个子系统提出请求,反之则不行。
  • Colleague 可以使用 Observer 模式和 Mediator 通信。