中介者模式
中介者模式又称为:调解人、控制器、Intermediary、Controller、Mediator。中介者是一种为设计模式,能让你减少对象之间混乱无序的依赖关系。该模式会限制对象之间的直接交互,迫使它们通过一个中介者对象进行合作。
问题
中介者模式其实就是一个中介,前面我们介绍了:命令模式,命令模式在两个类之间建立一个中间类来达到解耦,中介模式也相同,区别的是命令模式只能单向通信,而中介者能双向通信(类似于全双工)。
中介者模式非常常见,就如两人聊天,你和他说如何找富婆包养,而他却和你聊如何高效养猪,这么聊下去只能医院见,可想而知这个天很难聊下去。这时候你们就需要一个中间人进行双边翻译了,把你的爱好和他的爱好综合一下双向通信。
假设我们现在需要开发一个租房系统,租客只知道要租什么样的房子,房东知道自己有什么房子(软件开发中不能贴广告)。而这样必须要双双进行对话才能知道房子合不合适,那我是不是要在每个对象中进行交流呢?
解决方法
就如上例子可知,没有第三人的时候,这就高度耦合,没有人调解。增加第三人时你只要和第三人说喜欢的就行,传达交给第三人,这样便能直接交流并使其相互独立。租客和房东中增加一个中介,这样便能高效传达了~
结构
MediatorInterface:中介接口类;一般会暴露一个 send(发送对话) 方法; Mediator:中介具体类;用于 房东 和 租客 对话; Customer:中介客户抽象类;申明共同方法; Landlord、Tenant:具体的顾客类(房东、租客);包含自我业务逻辑的类。每个顾客都有一个指向中介的引用;
代码示例
中介接口
代码语言:javascript复制/**
* 中介接口
*/
interface MediatorInterface
{
/**
* 中间撮合消息
* @param string $message
* @param Customer $customer
* @return mixed
* @author chendashengpc
*/
public function send(string $message, Customer $customer);
}
中介具体类
代码语言:javascript复制/**
* 中介公司
*/
class Mediator implements MediatorInterface
{
/**
* 房东
* @var Customer
*/
public Customer $landlord;
/**
* 租客
* @var Customer
*/
public Customer $tenant;
public function send(string $message, Customer $customer)
{
if ($this->landlord == $customer) {
return $this->tenant->getMessage($message);
}
return $this->landlord->getMessage($message);
}
}
顾客抽象类
代码语言:javascript复制/**
* 顾客抽象类
*/
abstract class Customer
{
/**
* 中介
* @var MediatorInterface
*/
protected MediatorInterface $mediator;
/**
* 顾客姓名
* @var string
*/
public string $name;
public function __construct(string $name, MediatorInterface $mediator)
{
$this->name = $name;
$this->mediator = $mediator;
}
/**
* 获取对方信息
* @param string $message
* @return mixed
* @author chendashengpc
*/
abstract public function getMessage(string $message);
/**
* 和中介说
* @param string $message
* @return void
* @author chendashengpc
*/
public function declare(string $message)
{
return $this->mediator->send($message, $this);
}
}
具体类
房东
代码语言:javascript复制/**
* 房东
*/
class Landlord extends Customer
{
/**
*
* @return mixed|void
* @author chendashengpc
*/
public function getMessage(string $message)
{
return $this->name . '(房东) 获得对方消息:' . $message;
}
}
租客
代码语言:javascript复制/**
* 租客
*/
class Tenant extends Customer
{
/**
*
* @return mixed|void
* @author chendashengpc
*/
public function getMessage(string $message)
{
return $this->name . '(租客) 获得对方消息:' . $message;
}
}
客户端使用
代码语言:javascript复制/**
* 初始化中介
*/
$intermediary = new Mediator();
$li = new Landlord('李先生', $intermediary);
$chen = new Tenant('陈大剩', $intermediary);
$intermediary->landlord = $li;
$intermediary->tenant = $chen;
echo $chen->declare('需要找一个带独卫的单间!') . PHP_EOL;
echo $li->declare('这刚好有一间带独立卫浴的房间') . PHP_EOL;
输出
代码语言:javascript复制李先生(房东) 获得对方消息:需要找一个带独卫的单间!
陈大剩(租客) 获得对方消息:这刚好有一间带独立卫浴的房间
UML
优缺点
优点
- 单一职责原则。可以将多个组件间的交流抽取到同一位置,使其更易于理解和维护。
- 开闭原则。无需修改实际组件就能增加新的中介者。
- 可以减轻应用中多个组件间的耦合情况。
- 可以更方便地复用各个组件。
缺点
- 一段时间后, 中介者可能会演化成为上帝对象。
与其他模式的关系
责任链、 命令、中介者和观察者用于处理请求发送者和接收者之间的不同连接方式:
- 责任链按照顺序将请求动态传递给一系列的潜在接收者,直至其中一名接收者对请求进行处理。
- 命令在发送者和请求者之间建立单向连接。
- 中介者清除了发送者和请求者之间的直接连接,强制它们通过一个中介对象进行间接沟通。
- 观察者允许接收者动态地订阅或取消接收请求。