本文同步更新於blog
情境:以下是人脑的运作程序
<?php
namespace App\MediatorPattern\SayHello;
class Program
{
/**
* @param string $item
* @return string
*/
public function see($item)
{
switch ($item) {
case '认识的人':
return $this->sayHello();
break;
case '熟识的人':
return $this->waveHand();
break;
}
}
/**
* @param string $item
* @return string
*/
public function hear($item)
{
switch ($item) {
case '喜欢的人':
return $this->blush();
break;
case '讨厌的人':
return $this->pretendToLookBusy();
break;
}
}
private function sayHello()
{
return '[嘴巴]发出[你好]的声音';
}
private function waveHand()
{
return '[手]做出[挥手]的动作';
}
private function blush()
{
return '[脸]开始[发红]';
}
private function pretendToLookBusy()
{
return '[手]做出[装忙]的动作';
}
}
随着行为日趋复杂,我们可能会有更多的动作。
这些动作会联系着不同的器官。
因为强耦合,无论是器官的增加或是行为改变,
都会大大地影响既有程序码。
让我们用中介者模式改造它!
需求一:定义中介者介面 (Mediator)与合作者介面 (Colleague)
<?php
namespace App\MediatorPattern\SayHello\Contracts;
interface CentralNervousSystem
{
/**
* @param string $organName
* @param string $message
* @return string
*/
public function sendMessage($organName, $message);
}
<?php
namespace App\MediatorPattern\SayHello\Contracts;
interface Executable
{
/**
* @param string $message
* @return string
*/
public function execute($message);
}
需求二:定义实体中介者,来改变合作者间的依赖关系
<?php
namespace App\MediatorPattern\SayHello;
use App\MediatorPattern\SayHello\Contracts\CentralNervousSystem;
use App\MediatorPattern\SayHello\Abstracts\Organ;
class Brain implements CentralNervousSystem
{
/**
* @var Organ[]
*/
protected $organs = [];
/**
* @param string $organName
* @param string $message
* @return string
*/
public function sendMessage($organName, $message)
{
$organ = $this->organs[$organName];
return $organ->execute($message);
}
public function setOrgan(Organ $organ)
{
$organName = $organ->getName();
$this->organs[$organName] = $organ;
}
}
<?php
namespace App\MediatorPattern\SayHello\Abstracts;
use App\MediatorPattern\SayHello\Contracts\Executable;
use App\MediatorPattern\SayHello\Brain;
abstract class Organ implements Executable
{
/**
* @var string
*/
protected $name = 'Unknown';
/**
* @var Brain
*/
protected $brain;
public function __construct(Brain $brain)
{
$this->brain = $brain;
}
public function getName()
{
return $this->name;
}
}
<?php
namespace App\MediatorPattern\SayHello;
use App\MediatorPattern\SayHello\Abstracts\Organ;
class Eye extends Organ
{
/**
* @var string
*/
protected $name = '眼睛';
/**
* @param string $message
* @return string
*/
public function execute($message)
{
switch ($message) {
case '认识的人':
return $this->brain->sendMessage('嘴巴', '你好');
break;
case '熟识的人':
return $this->brain->sendMessage('手', '挥手');
break;
}
}
}
<?php
namespace App\MediatorPattern\SayHello;
use App\MediatorPattern\SayHello\Abstracts\Organ;
class Ear extends Organ
{
/**
* @var string
*/
protected $name = '耳朵';
/**
* @param string $message
* @return string
*/
public function execute($message)
{
switch ($message) {
case '喜欢的人':
return $this->brain->sendMessage('脸', '发红');
break;
case '讨厌的人':
return $this->brain->sendMessage('手', '装忙');
break;
}
}
}
<?php
namespace App\MediatorPattern\SayHello;
use App\MediatorPattern\SayHello\Abstracts\Organ;
class Hand extends Organ
{
protected $name = '手';
/**
* @param string $message
* @return string
*/
public function execute($message)
{
return "[手]做出[$message]的动作";
}
}
<?php
namespace App\MediatorPattern\SayHello;
use App\MediatorPattern\SayHello\Abstracts\Organ;
class Mouth extends Organ
{
/**
* @var string
*/
protected $name = '嘴巴';
/**
* @param string $message
* @return string
*/
public function execute($message)
{
return "[嘴巴]发出[$message]的声音";
}
}
<?php
namespace App\MediatorPattern\SayHello;
use App\MediatorPattern\SayHello\Abstracts\Organ;
class Face extends Organ
{
/**
* @var string
*/
protected $name = '脸';
/**
* @param string $message
* @return string
*/
public function execute($message)
{
return "[脸]开始[$message]";
}
}
以这个范例来说,中介者是大脑,合作者则是各个器官。
当A器官要呼叫B器官,执行某些动作时,
会透过大脑,使得A器官不必知道真正的B器官是谁(松耦合)。
需求三:改写既有程序码
<?php
namespace App\MediatorPattern\SayHello;
use App\MediatorPattern\SayHello\Brain;
use App\MediatorPattern\SayHello\Eye;
use App\MediatorPattern\SayHello\Mouth;
use App\MediatorPattern\SayHello\Hand;
use App\MediatorPattern\SayHello\Ear;
use App\MediatorPattern\SayHello\Face;
class Program
{
/**
* @var Brain
*/
protected $brain;
/**
* @var Eye
*/
protected $eye;
/**
* @var Mouth
*/
protected $mouth;
/**
* @var Hand
*/
protected $hand;
/**
* @var Ear
*/
protected $ear;
/**
* @var Face
*/
protected $face;
public function __construct()
{
$this->brain = $this->resolveBrainAndOrgans();
}
/**
* @param string $item
* @return string
*/
public function see($item)
{
return $this->eye->execute($item);
}
/**
* @param string $item
* @return string
*/
public function hear($item)
{
return $this->ear->execute($item);
}
private function resolveBrainAndOrgans()
{
$this->brain = new Brain();
$this->resolveOrgans();
$this->brain->setOrgan($this->eye);
$this->brain->setOrgan($this->mouth);
$this->brain->setOrgan($this->hand);
$this->brain->setOrgan($this->ear);
$this->brain->setOrgan($this->face);
}
private function resolveOrgans()
{
$this->eye = new Eye($this->brain);
$this->mouth = new Mouth($this->brain);
$this->hand = new Hand($this->brain);
$this->ear = new Ear($this->brain);
$this->face = new Face($this->brain);
}
}
[单一职责原则]
我们将器官的功能与器官间的关系视作两种不同的职责。
藉由大脑(中介者)负责联络各个器官(合作者)执行对应的行为。
[开放封闭原则]
无论是新增/修改器官,或者新增/修改器官间的关系,
我们都不会改动到所有程序码。
[介面隔离原则]
中介者介面:负责传送器官间的讯息。
合作者介面:负责执行该器官的功能。
[依赖反转原则]
大脑依赖於合作者介面。
器官负责实作合作者介面。
最後附上类别图:
(注:若不熟悉 UML 类别图,可参考UML类别图说明。)
ʕ •ᴥ•ʔ:早上刚睡醒时,想到的范例。
<<: Outlook PST Repair Tool - Repair PST data file
>>: 【图解演算法教学】Bubble Sort 的大队接力赛
这次主要跟着三位大神学习 Vue3 重新认识 Vue.js | Kuro Hsu Vue3.0学习教...
现在终於可以开始讲 Grid 单元的事情了,虽然可以讲的事情可能不多,绝大部分会围绕在造成容器影响的...
mutable 与 Immutable 比较 Immutable object 不可变物件 物件被创...
阵列可以一次宣告大量的变数,有节省时间、空间的优点。在JavaScript里,阵列可储存不同型态的值...
今天整理程序的基础知识,所有的程序都是由这些基础建构起来的。 我觉得程序跑起来真正重要的观念大概有三...