初识设计模式——中介者模式(Mediator Pattern)

cuixiaogang

中介者模式(Mediator Pattern)是一种行为设计模式,它能减少对象之间混乱无序的依赖关系。该模式会限制对象之间的直接交互,促使它们通过一个中介者对象进行间接沟通。如此一来,对象之间的耦合度得以降低,并且能更轻松地对系统进行修改和扩展。

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

中介者模式的构成

  • 抽象中介者(Mediator):定义了中介者与同事对象之间交互的接口。
  • 具体中介者(ConcreteMediator):实现了抽象中介者的接口,负责协调各个同事对象之间的交互,知道并管理所有同事对象。
  • 抽象同事类(Colleague):定义了同事对象的接口,包含了同事对象与中介者交互的方法。
  • 具体同事类(ConcreteColleague):实现了抽象同事类的接口,每一个具体同事类都知道中介者对象,通过中介者进行与其他同事对象的通信。

中介者模式结构图

示例

场景

在WEB开发中,经常需要对表单传入的参数进行校验,而校验的逻辑跟表单字段之间可能存在各种各样的依赖关系,这时可以使用中介者模式来解耦校验逻辑和表单字段之间的关系

代码

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
<?php
// 抽象中介者
abstract class Mediator {
abstract public function validateInput();
abstract public function validateCheckbox();
abstract public function handleSubmit();
}

// 抽象同事类
abstract class Colleague {
protected $mediator;

public function setMediator(Mediator $mediator) {
$this->mediator = $mediator;
}
}

// 具体中介者
class FormMediator extends Mediator {
private $input;
private $checkbox;
private $button;

public function __construct(Colleague $input, Colleague $checkbox, Colleague $button) {
$this->input = $input;
$this->checkbox = $checkbox;
$this->button = $button;

$this->input->setMediator($this);
$this->checkbox->setMediator($this);
$this->button->setMediator($this);
}

// 验证输入字段
public function validateInput() {
return strlen($this->input->getValue()) > 0;
}

// 验证复选框
public function validateCheckbox() {
return $this->checkbox->isChecked();
}

// 处理表单提交
public function handleSubmit() {
if ($this->validateInput() && $this->validateCheckbox()) {
echo '表单提交成功';
} else {
echo '表单验证失败';
}
}
}

// 输入字段
class InputField extends Colleague {
private $value;

public function setValue($value) {
$this->value = $value;
$this->mediator->validateInput();
}

public function getValue() {
return $this->value;
}
}

// 复选框
class Checkbox extends Colleague {
private $checked;

public function setChecked($checked) {
$this->checked = $checked;
$this->mediator->validateCheckbox();
}

public function isChecked() {
return $this->checked;
}
}

// 提交按钮
class SubmitButton extends Colleague {
public function click() {
$this->mediator->handleSubmit();
}
}

// 使用示例
$input = new InputField();
$checkbox = new Checkbox();
$button = new SubmitButton();

$mediator = new FormMediator($input, $checkbox, $button);

$input->setValue('example');
$checkbox->setChecked(true);
$button->click();

代码含义

上面的代码中,FormMediator 类是中介者,它协调 InputField、Checkbox 和 SubmitButton 之间的交互。当输入字段值改变、复选框状态改变或者提交按钮被点击时,会通知中介者执行相应处理。

UML类图

UML类图

中介者模式的优缺点

优点

  • 降低耦合度:各个同事对象之间不再直接相互引用,而是通过中介者进行通信,使得对象之间的耦合度大大降低。
  • 便于维护和扩展:当需要修改或添加新的交互逻辑时,只需修改或扩展中介者类,而不需要修改各个同事类。
  • 符合迪米特法则:每个对象只和中介者通信,减少了对象之间的依赖关系。

缺点

  • 中介者类过于复杂:随着同事对象的增加,中介者类的逻辑会变得越来越复杂,维护成本也会相应增加。
  • 系统性能受到影响:由于所有的交互都通过中介者进行,可能会导致系统性能下降。

中介者模式的适用场景

  • 表单验证与提交:在 Web 页面上,表单往往包含多个输入字段(像文本框、下拉框、复选框等),同时还有提交按钮。不同的输入字段或许有不同的验证规则,并且在提交表单时,需要保证所有字段都通过验证。这时就可以运用中介者模式,让中介者负责协调各个输入字段的验证以及表单的提交操作。
  • 组件间通信:现代 Web 应用常常由多个组件构成,这些组件之间可能需要进行数据传递和交互。若组件之间直接相互引用,会使代码的耦合度变高,难以维护。借助中介者模式,能够让所有组件都与中介者进行通信,从而降低组件之间的耦合度。
  • 页面导航与状态管理:在单页面应用(SPA)中,页面的导航和状态管理是非常关键的功能。不同的页面组件可能需要根据当前的路由状态来显示不同的内容,并且在用户进行导航操作时,需要更新页面的状态。中介者模式可以用来协调页面组件之间的导航和状态更新。
  • 实时通信系统:在实时通信系统(例如聊天应用、在线协作工具等)中,多个用户之间需要进行消息的传递和交互。中介者模式可以充当服务器端的角色,负责接收和转发用户之间的消息,从而实现用户之间的实时通信。

中介者模式与策略模式的区别

定义和目的

  • 中介者模式:其核心是通过引入一个中介对象,让多个对象之间的交互都通过这个中介对象来进行,从而降低这些对象之间的耦合度。它主要用于处理多个对象之间复杂的交互关系,使各个对象无需显式地相互引用,提高系统的可维护性和可扩展性。
  • 策略模式:定义了一系列的算法,并将每个算法封装起来,使它们可以相互替换。策略模式让算法的变化独立于使用算法的客户端,目的是为了在运行时根据不同的情况选择不同的算法。

结构和组成

  • 中介者模式:包含中介者接口、具体中介者、同事类接口和具体同事类。中介者负责协调各个同事类之间的交互,同事类只需要与中介者进行通信,而不需要了解其他同事类的情况。
  • 策略模式:包含策略接口、具体策略类和上下文类。策略接口定义了算法的公共接口,具体策略类实现了具体的算法,上下文类持有一个策略接口的引用,根据需要选择不同的具体策略类。

应用场景

  • 中介者模式:适用于对象之间存在复杂的网状交互关系,导致代码难以维护和扩展的情况。例如,在一个聊天系统中,多个用户之间的消息传递可以通过中介者(服务器)来实现,用户只需要与服务器进行通信,而不需要直接与其他用户交互。
  • 策略模式:适用于需要在不同的算法之间进行动态切换的场景。例如,在一个电商系统中,根据不同的促销活动(如满减、折扣、赠品等)选择不同的计算价格的算法。