在软件工程领域，**中介者模式**定义了一个中介者对象，该对象封装了系统中对象间的交互方式。 由于它可以在运行时改变程序的行为，这种模式是一种行为型模式 。

通常程序由大量的类组成，这些类中包含程序的逻辑和运算。 然而，当开发者将更多的类加入到程序中之后，类间交互关系可能变得更为复杂，这会使得代码变得更加难以阅读和维护，尤其是在重构的时候。 此外，程序将会变得难以修改，因为对其所做的任何修改都有可能影响到其它几个类中的代码。

在**中介者模式**中，对象间的通信过程被封装在一个**中介者**（调解人）对象之中。 对象之间不再直接交互，而是通过调解人进行交互。 这么做可以减少可交互对象间的依赖，从而降低耦合。

概述
--

中介者模式是23个周知模式（ 即*GoF设计模式*）中的一个，GoF设计模式旨在提供重复出现的设计问题的解决方案，以编写灵活和可复用的面向对象软件。也就是说，使对象更加易于实现、修改、测试和复用。

中介者设计模式可以解决什么问题？

* 避免一组相互交互的对象之间出现紧耦合。
* 能够独立地改变一组对象之间的交互关系而不影响其他对象。

使用直接逐个访问并更新彼此的方式进行对象间的交互灵活性低，因为这种方式使对象彼此间紧密耦合，导致不可能单独修改类间交互关系本身，而不影响关系中进行交互的类。并且这种方式会令对象变得无法复用，并且难以测试。

由于*紧耦合的对象*过多了解其他对象的内部细节，这种对象难以实现、修改、测试以及复用。

中介者模式如何解决上述问题？

* 定义一个独立的中介者(调解员)的对象，封装一组对象之间的交互关系。
* 对象将自己的交互委托给中介者执行，避免直接与其他对象进行交互。

对象利用中介者对象与其他对象进行间接交互，中介者对象负责控制和协调交互关系，这么做可使得对象间*松耦合*。这些对象只访问中介者，不了解其他对象的细节。

另见UML类图和时序图如下。

定义
--

中介者模式是为了"定义一个封装了对象间交互关系的对象"。这种方式避免了显式调用其他类，促进了类间的松耦合，并且使得类间交互关系本身可以单独修改。客户类可以使用中介者向其他客户类发送信息，并且通过中介者引发的事件收到信息。

结构
--

### UML类图和时序图

一个中介者模式典型实现的UML类图和时序图。 
在以上 UML 类图中，类 `Colleague1` 和 `Colleague2` 不引用和更新彼此。
相反，它们引用一个通用的 `Mediator` 接口以实现类间交互的控制和协调(通过`mediate()`)，这使得它们独立于类间交互的具体细节。
类 `Mediator1` 实现了类 `Colleague1` 和 `Colleague2`之间的交互细节。

上述 UML 时序图
显示了这些类之间在运行时的交互过程： 
在这个例子中，一个 `Mediator1` 对象 
中介，即控制和协调了 `Colleague1` 和 `Colleague2`的对象之间的交互。

如果 `Colleague1` 的对象需要与 `Colleague2` 的对象进行交互，例如更新或者同步状态，
`Colleague1` 调用`Mediator1` 对象的 `mediate(this)`方法，
以此得到对 `Colleague1` 对象（自己）的改动信息，并且在 `Colleague2`的对象上执行 `action2()` 方法。

此后，
`Colleague2` 对象调用`Mediator1` 对象的 `mediate(this)`方法，
得到对`Colleague2` （自己）的修改的数据，并且对`Colleague1` 对象调用`action1()` 方法。

### 类图

中介者设计模式
参与者
**Mediator** - 定义 *Colleague* 对象之间的交互接口。

**ConcreteMediator** -实现了*Mediator*接口，并且协调 *Colleague*对象之间的交互，知道所有的 *Colleagues* 对象以及其交互目的。

**Colleague** -定义了通过*Mediator*与其他*Colleague*对象交互的接口。

**ConcreteColleague** -实现了*Colleague*接口，并且通过它的*Mediator*与其他*Colleague*交互。

范例
--

### C#

中介者模式确保了构件之间的松耦合，使得它们不直接调用彼此，而是通过中介者调用彼此。 在下面的例子中，调解人注册了所有的构件，然后调用了它们的SetState方法。

```
public interface IComponent
{
 void SetState(object state);
}

public class Component1 : IComponent
{
 public void SetState(object state)
 {
 throw new NotImplementedException();
 }
}

public class Component2 : IComponent
{
 public void SetState(object state)
 {
 throw new NotImplementedException();
 }
}

// Mediates the common tasks
public class Mediator
{
 public IComponent Component1 { get; set; }
 public IComponent Component2 { get; set; }

 public void ChangeState(object state)
 {
 this.Component1.SetState(state);
 this.Component2.SetState(state);
 }
}

```
一个聊天室，或者一个需要客户彼此间每次发送消息之后执行动作的系统（对聊天室来说就是每个人之间发送消息）可以使用中介者模式。但实际上对聊天室使用中介者模式只在包含远程功能时有用。 原生的套接字不允许委託回呼函式（即通过中介者类订阅的 MessageReceived 事件）。

```
public delegate void MessageReceivedEventHandler(string message, string from);

public class Mediator
{
 public event MessageReceivedEventHandler MessageReceived;

 public void Send(string message, string from)
 {
 if (MessageReceived != null)
 {
 Console.WriteLine("Sending '{0}' from {1}", message, from);
 MessageReceived(message, from);
 }
 }
}

public class Person
{
 private Mediator \_mediator;

 public string Name { get; set; }

 public Person(Mediator mediator, string name)
 {
 Name = name;
 \_mediator = mediator;
 \_mediator.MessageReceived += new MessageReceivedEventHandler(Receive);
 }

 private void Receive(string message, string from)
 {
 if (from != Name)
 Console.WriteLine("{0} received '{1}' from {2}", Name, message, from);
 }

 public void Send(string message)
 {
 \_mediator.Send(message, Name);
 }
}

```

### Java

在以下示例中，一个中介者对象控制了三个互相交互的按钮的状态，为此它有设置状态的三个方法：`book()`, `view()` 和 `search()`。 当相应的按钮被激活时，对应的方法通过`execute()`方法被调用。

于是这里在交互中每个交互的参与者（本例中即按钮）将自己的行为提交给中介者并且由中介者将这些行为转给对应的参与者。

```
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

//Colleague interface
interface Command {
 void execute();
}

//Abstract Mediator
interface Mediator {
 void book();
 void view();
 void search();
 void registerView(BtnView v);
 void registerSearch(BtnSearch s);
 void registerBook(BtnBook b);
 void registerDisplay(LblDisplay d);
}

//Concrete mediator
class ParticipantMediator implements Mediator {

 BtnView btnView;
 BtnSearch btnSearch;
 BtnBook btnBook;
 LblDisplay show;

 //....
 public void registerView(BtnView v) {
 btnView = v;
 }

 public void registerSearch(BtnSearch s) {
 btnSearch = s;
 }

 public void registerBook(BtnBook b) {
 btnBook = b;
 }

 public void registerDisplay(LblDisplay d) {
 show = d;
 }

 public void book() {
 btnBook.setEnabled(false);
 btnView.setEnabled(true);
 btnSearch.setEnabled(true);
 show.setText("booking...");
 }

 public void view() {
 btnView.setEnabled(false);
 btnSearch.setEnabled(true);
 btnBook.setEnabled(true);
 show.setText("viewing...");
 }

 public void search() {
 btnSearch.setEnabled(false);
 btnView.setEnabled(true);
 btnBook.setEnabled(true);
 show.setText("searching...");
 }
 
}

//A concrete colleague
class BtnView extends JButton implements Command {

 Mediator med;

 BtnView(ActionListener al, Mediator m) {
 super("View");
 addActionListener(al);
 med = m;
 med.registerView(this);
 }

 public void execute() {
 med.view();
 }
 
}

//A concrete colleague
class BtnSearch extends JButton implements Command {

 Mediator med;

 BtnSearch(ActionListener al, Mediator m) {
 super("Search");
 addActionListener(al);
 med = m;
 med.registerSearch(this);
 }

 public void execute() {
 med.search();
 }
 
}

//A concrete colleague
class BtnBook extends JButton implements Command {

 Mediator med;

 BtnBook(ActionListener al, Mediator m) {
 super("Book");
 addActionListener(al);
 med = m;
 med.registerBook(this);
 }

 public void execute() {
 med.book();
 }

}

class LblDisplay extends JLabel {

 Mediator med;

 LblDisplay(Mediator m) {
 super("Just start...");
 med = m;
 med.registerDisplay(this);
 setFont(new Font("Arial", Font.BOLD, 24));
 }

}

class MediatorDemo extends JFrame implements ActionListener {

 Mediator med = new ParticipantMediator();

 MediatorDemo() {
 JPanel p = new JPanel();
 p.add(new BtnView(this, med));
 p.add(new BtnBook(this, med));
 p.add(new BtnSearch(this, med));
 getContentPane().add(new LblDisplay(med), "North");
 getContentPane().add(p, "South");
 setSize(400, 200);
 setVisible(true);
 }

 public void actionPerformed(ActionEvent ae) {
 Command comd = (Command) ae.getSource();
 comd.execute();
 }

 public static void main(String[] args) {
 new MediatorDemo();
 }

}

```

另见
--

* Data mediation
* 设计模式：可复用面向对象软件的基础, 本书引起计算机科学界对设计模式的研究
* 设计模式(计算机)，解决常见软件设计问题的标准化方法

参考文献
----

1. ↑  Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides.. Addison Wesley. 1994: 273ff. ISBN 0-201-63361-2.
2. ↑ . w3sDesign.com.  [2017-08-12]. （原始内容存档于2018-12-16）.
3. ↑  Gang Of Four
4. ↑ . w3sDesign.com.  [2017-08-12]. （原始内容存档于2018-12-16）.

外部链接
----

* Mediator Design Pattern
* Is the use of the mediator pattern recommend? - Stack Overflow（页面存档备份，存于）

|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 

| * 
* 论
* 编
软件设计模式 |
| --- |
|  |
| 设计模式 | 

|  |  |
| --- | --- |
| 创建型 | 
* 抽象工厂
* 生成器
* 工厂方法
* 惰性初始
* 原型
* 单例

 |
|  |
| 结构型 | 
* 适配器
* 桥接
* Composite（英语：）
* 修饰
* 外观
* 享元
* 代理

 |
|  |
| 行为型 | 
* 责任链
* 命令
* Interpreter（英语：）
* 迭代器
* 中介者
* Memento（英语：）
* 观察者
* Specification（英语：）
* State（英语：）
* 策略
* 模板方法
* 访问者

 |

 |
|  |
| 并行模式 | 
* 主动对象（英语：）
* 阻止（英语：）
* Binding properties（英语：）
* 双重检查锁定模式
* 异步方法调用
* Guarded suspension（英语：）
* Join（英语：）
* 锁
* Messaging（英语：）
* 监视器
* Proactor（英语：）
* 反应器
* 读写锁
* 调度
* 线程池
* 线程局部存储

 |
|  |
| 架构模式 | 
* ADR（英语：）
* Broker（英语：）
* 主從式架構
* CBD
* DAO
* 主动记录
* 数据映射器
* DDD
* Data transfer object（英语：）
* Front controller（英语：）
* Identity map（英语：）
* Interceptor（英语：）
* 控制反转
* MVC
* 微服務
* MVP
* 單體式應用程式
* 多层架构
* Naked objects（英语：）
* P2P
* 发布/订阅
* REST
* SOA
* Specification（英语：）

 |
|  |
| 云分布式 | 
* 断路器
* CQRS（英语：）
* 补偿交易（英语：）
* 索引表
* 领导者选举（英语：）
* MapReduce
* 物化视图（英语：）
* 管道
* 过滤器（英语：）
* 发布/订阅
* 分片（英语：）
* 节流（英语：）

 |
|  |
| 其他模式 | 
* Blackboard（英语：）
* Business delegate（英语：）
* Composite entity（英语：）
* 委托
* 依赖注入
* Intercepting filter（英语：）
* 惰性載入
* Method chaining（英语：）
* 模拟对象
* 空对象
* 对象池
* Servant（英语：）
* Twin（英语：）
* Type tunnel（英语：）

 |
|  |
| 书籍 | 
* 设计模式：可复用面向对象软件的基础
* 代碼大全
* 企业集成模式（英语：）

 |
|  |
| 人物 | 
* 克里斯托佛·亚历山大
* 埃里希·伽瑪
* Ralph Johnson（英语：）
* John Vlissides（英语：）
* 葛來迪·布區
* 肯特·貝克
* 沃德·坎宁安
* 马丁·福勒
* Robert Martin（英语：）
* Jim Coplien（英语：）
* Douglas Schmidt（英语：）
* Linda Rising

 |
|  |
| 社区 | 
* The Hillside Group（英语：）
* The Portland Pattern Repository（英语：）

 |

 |