概述
- 减少对象之间混乱无序的依赖关系,限制对象之间的直接交互,迫使他们通过一个中介者进行合作
- 软件构建过程中,经常会出现多个对象互相关联交互的情况,对象之间常常会维持一种复杂的引用关系,如果遇到一些需求的更改,这种直接的引用关系将面临不断的变化
- 这种情况下,可使用一个“中介对象”来管理对象间的关联关系,避免互相的对象之间的禁耦合引用关系,从而更好地抵御变化
- 用一个中介对象来封装一系列对象的交互。中介者使各对象不需要显式的相互引用(编译依赖->运行依赖),从而使其耦合松散(管理变化),而且可以独立地改变它们之间的交互
- 发送者不知道最终由谁处理请求,接收者也不知道最初是谁发出了请求
- 空心三角表示继承,实心箭头表示指针指向
- Facade模式是解耦系统间(单向)的对象关联关系,Mediator模式是解耦系统内各个对象间(双向)的关联关系
- 将多个对象间复杂的关联关系解耦,Mediator将多个对象间的控制逻辑进行几种管理,变“多个对象互相关联”为“多个对象和一个中介者关联”,简化了系统的维护,抵御了可能的变化
- 随着控制逻辑的复杂化,Mediator具体对象的实现可能相当复杂,这时可对Mediator对象进行分解处理
场景
- 飞机驾驶员不会通过相互沟通来决定下一架降落的飞机,所有沟通都通过控制塔台进行
- 接收到事件通知后,对话框确认负责处理事件的元素并重定向请求,减少按钮、复选框、文本标签之间相互依赖关系
- 中国加入WTO前分别和各个国家相互贸易,加入后通过WTO和各个国家相互贸易
- MVC 框架,其中C(控制器)就是 M(模型)和 V(视图)的中介者
- 多个用户向聊天室发送消息,聊天室向所有的用户显示消息
结构
- 组件类:各种包含业务逻辑的类,每个组件都有一个指向中介者的引用,该引用被声明为中介者接口类型
- 中介者接口:声明了与组件交流的方法
- 具体中介者:封装了多种组件的关系,保存所有组件的引用并对其进行管理
联系
- 责任链模式、命令模式、中介者模式、观察者模式用于处理发送者和接收者之间的不同连接方式
- 外观模式和中介者模式都尝试在大量紧密耦合的类中组织起合作
- 中介者的组件依赖同一个中介者对象,观察者是在对象之间建立动态的单向连接,使得部分对象可以作为其他对象的附属发挥作用
示例1
1 // 中介者接口声明了一个能让组件将各种事件通知给中介者的方法。中介者可对这 2 // 些事件做出响应并将执行工作传递给其他组件。 3 interface Mediator is 4 method notify(sender: Component, event: string) 5 6 7 // 具体中介者类可解开各组件之间相互交叉的连接关系并将其转移到中介者中。 8 class AuthenticationDialog implements Mediator is 9 private field title: string 10 private field loginOrRegisterChkBx: Checkbox 11 private field loginUsername, loginPassword: Textbox 12 private field registrationUsername, registrationPassword, 13 registrationEmail: Textbox 14 private field okBtn, cancelBtn: Button 15 16 constructor AuthenticationDialog() is 17 // 创建所有组件对象并将当前中介者传递给其构造函数以建立连接。 18 19 // 当组件中有事件发生时,它会通知中介者。中介者接收到通知后可自行处理, 20 // 也可将请求传递给另一个组件。 21 method notify(sender, event) is 22 if (sender == loginOrRegisterChkBx and event == "check") 23 if (loginOrRegisterChkBx.checked) 24 title = "登录" 25 // 1. 显示登录表单组件。 26 // 2. 隐藏注册表单组件。 27 else 28 title = "注册" 29 // 1. 显示注册表单组件。 30 // 2. 隐藏登录表单组件。 31 32 if (sender == okBtn && event == "click") 33 if (loginOrRegister.checked) 34 // 尝试找到使用登录信息的用户。 35 if (!found) 36 // 在登录字段上方显示错误信息。 37 else 38 // 1. 使用注册字段中的数据创建用户账号。 39 // 2. 完成用户登录工作。 … 40 41 42 // 组件会使用中介者接口与中介者进行交互。因此只需将它们与不同的中介者连接 43 // 起来,你就能在其他情境中使用这些组件了。 44 class Component is 45 field dialog: Mediator 46 47 constructor Component(dialog) is 48 this.dialog = dialog 49 50 method click() is 51 dialog.notify(this, "click") 52 53 method keypress() is 54 dialog.notify(this, "keypress") 55 56 // 具体组件之间无法进行交流。它们只有一个交流渠道,那就是向中介者发送通知。 57 class Button extends Component is 58 // ... 59 60 class Textbox extends Component is 61 // ... 62 63 class Checkbox extends Component is 64 method check() is 65 dialog.notify(this, "check") 66 // ...
示例2
1 #include <iostream> 2 #include <string> 3 using namespace std; 4 5 class BaseComponent; 6 class Mediator{ 7 public: 8 virtual void Notify(BaseComponent *sender,string event) const = 0; 9 }; 10 11 class BaseComponent{ 12 protected: 13 Mediator *mediator_; 14 15 public: 16 BaseComponent(Mediator *mediator = nullptr):mediator_(mediator){ 17 } 18 void set_mediator(Mediator *mediator){ 19 this->mediator_ = mediator; 20 } 21 }; 22 23 class Component1:public BaseComponent{ 24 public: 25 void DoA(){ 26 cout << "Component 1 dose A. "; 27 this->mediator_->Notify(this,"A"); 28 } 29 void DoB(){ 30 cout << "Component 1 dose B. "; 31 this->mediator_->Notify(this,"B"); 32 } 33 }; 34 35 class Component2:public BaseComponent{ 36 public: 37 void DoC(){ 38 cout << "Component 2 dose C. "; 39 this->mediator_->Notify(this,"C"); 40 } 41 void DoD(){ 42 cout << "Component 2 dose D. "; 43 this->mediator_->Notify(this,"D"); 44 } 45 }; 46 47 class ConcreteMediator:public Mediator{ 48 private: 49 Component1 *component1_; 50 Component2 *component2_; 51 52 public: 53 ConcreteMediator(Component1 *c1,Component2 *c2):component1_(c1),component2_(c2){ 54 this->component1_->set_mediator(this); 55 this->component2_->set_mediator(this); 56 } 57 void Notify(BaseComponent *sender,string event) const override{ 58 if(event == "A"){ 59 cout << "Mediator reacts on A and triggers following operations: "; 60 this->component2_->DoC(); 61 } 62 if (event == "D") { 63 cout << "Mediator reacts on D and triggers following operations: "; 64 this->component1_->DoB(); 65 this->component2_->DoC(); 66 } 67 } 68 }; 69 70 void ClientCode(){ 71 Component1 *c1 = new Component1; 72 Component2 *c2 = new Component2; 73 ConcreteMediator *mediator = new ConcreteMediator(c1,c2); 74 cout << "Client triggers operation A. "; 75 c1->DoA(); 76 cout << " "; 77 cout << "Client triggers operation D. "; 78 c2->DoD(); 79 80 delete c1; 81 delete c2; 82 delete mediator; 83 } 84 85 int main(){ 86 ClientCode(); 87 return 0; 88 }
Client triggers operation A. Component 1 does A. Mediator reacts on A and triggers following operations: Component 2 does C. Client triggers operation D. Component 2 does D. Mediator reacts on D and triggers following operations: Component 1 does B. Component 2 does C.
示例3
1 import java.util.Date; 2 3 public class ChatRoom { 4 public static void showMessage(User user, String message) { 5 System.out.println(new Date().toString() 6 + " [" + user.getName() + "]: " + message); 7 } 8 } 9 10 public class User { 11 private String name; 12 13 public String getName() { 14 return name; 15 } 16 17 public User(String name) { 18 this.name = name; 19 } 20 21 public void sendMessage(String message) { 22 ChatRoom.showMessage(this, message); 23 } 24 } 25 26 public class MediatorPatternDemo { 27 public static void main(String[] args) { 28 User robert = new User("Robert"); 29 User john = new User("John"); 30 31 robert.sendMessage("Hi! John!"); 32 john.sendMessage("Hello! Robert!"); 33 } 34 }
Fri Jun 12 19:45:39 CST 2020 [Robert]: Hi! John!
Fri Jun 12 19:45:39 CST 2020 [John]: Hello! Robert!
参考
https://refactoringguru.cn/design-patterns/mediator