Pattern: 中介者模式
Class Diagram: 打招呼
情境:以下是人腦的運作程式
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
| <?php
namespace App\MediatorPattern\SayHello;
class Program {
public function see($item) { switch ($item) { case '認識的人': return $this->sayHello(); break;
case '熟識的人': return $this->waveHand(); break; } }
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)
- 使用中樞神經系統作為中介者介面 (Mediator)
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?php
namespace App\MediatorPattern\SayHello\Contracts;
interface CentralNervousSystem {
public function sendMessage($organName, $message); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| <?php
namespace App\MediatorPattern\SayHello\Contracts;
interface Executable {
public function execute($message); }
|
需求二:定義實體中介者,來改變合作者間的依賴關係
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
| <?php
namespace App\MediatorPattern\SayHello;
use App\MediatorPattern\SayHello\Contracts\CentralNervousSystem; use App\MediatorPattern\SayHello\Abstracts\Organ;
class Brain implements CentralNervousSystem {
protected $organs = [];
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; } }
|
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
| <?php
namespace App\MediatorPattern\SayHello\Abstracts;
use App\MediatorPattern\SayHello\Contracts\Executable; use App\MediatorPattern\SayHello\Brain;
abstract class Organ implements Executable {
protected $name = 'Unknown';
protected $brain;
public function __construct(Brain $brain) { $this->brain = $brain; }
public function getName() { return $this->name; } }
|
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
| <?php
namespace App\MediatorPattern\SayHello;
use App\MediatorPattern\SayHello\Abstracts\Organ;
class Eye extends Organ {
protected $name = '眼睛';
public function execute($message) { switch ($message) { case '認識的人': return $this->brain->sendMessage('嘴巴', '你好'); break;
case '熟識的人': return $this->brain->sendMessage('手', '揮手'); break; } } }
|
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
| <?php
namespace App\MediatorPattern\SayHello;
use App\MediatorPattern\SayHello\Abstracts\Organ;
class Ear extends Organ {
protected $name = '耳朵';
public function execute($message) { switch ($message) { case '喜歡的人': return $this->brain->sendMessage('臉', '發紅'); break;
case '討厭的人': return $this->brain->sendMessage('手', '裝忙'); break; } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <?php
namespace App\MediatorPattern\SayHello;
use App\MediatorPattern\SayHello\Abstracts\Organ;
class Hand extends Organ { protected $name = '手';
public function execute($message) { return "[手]做出[$message]的動作"; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <?php
namespace App\MediatorPattern\SayHello;
use App\MediatorPattern\SayHello\Abstracts\Organ;
class Mouth extends Organ {
protected $name = '嘴巴';
public function execute($message) { return "[嘴巴]發出[$message]的聲音"; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <?php
namespace App\MediatorPattern\SayHello;
use App\MediatorPattern\SayHello\Abstracts\Organ;
class Face extends Organ {
protected $name = '臉';
public function execute($message) { return "[臉]開始[$message]"; } }
|
以這個範例來說,中介者是大腦,合作者則是各個器官。
當A器官要呼叫B器官,執行某些動作時,
會透過大腦,使得A器官不必知道真正的B器官是誰(鬆耦合)。
需求三:改寫既有程式碼
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
| <?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 {
protected $brain;
protected $eye;
protected $mouth;
protected $hand;
protected $ear;
protected $face;
public function __construct() { $this->brain = $this->resolveBrainAndOrgans(); }
public function see($item) { return $this->eye->execute($item); }
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); } }
|
[單一職責原則]
我們將器官的功能與器官間的關係視作兩種不同的職責。
藉由大腦(中介者)負責聯絡各個器官(合作者)執行對應的行為。
[開放封閉原則]
無論是新增/修改器官,或者新增/修改器官間的關係,
我們都不會改動到所有程式碼。
[介面隔離原則]
中介者介面:負責傳送器官間的訊息。
合作者介面:負責執行該器官的功能。
[依賴反轉原則]
大腦依賴於合作者介面。
器官負責實作合作者介面。
ʕ •ᴥ•ʔ:早上剛睡醒時,想到的範例。