本文同步發佈於blog
情境:以下是某才藝表演
<?php
namespace App\AdapterPattern\TalentShow;
class Program
{
/**
* @return array
*/
public function run()
{
$result = [];
$pianoPlayer = new PianoPlayer();
$result[] = $pianoPlayer->play();
$jokeTeller = new JokeTeller();
$result[] = $jokeTeller->tell();
return $result;
}
}
主持人覺得需要知道,每位表演者的表演方式,有些麻煩。
希望我們定義一個統一的介面,讓他的主持工作能更順利。
需求一:定義表演介面,使得表演項目能夠被管理
隨著項目變多,每個人的表演都不一樣。
可能會有彈鋼琴、拉扯鈴、講笑話、演話劇等。
但是這些項目,未必都是為了才藝表演而存在。
讓我們以此為基礎,切分兩者的職責。
<?php
namespace App\AdapterPattern\TalentShow\Contracts;
interface ShowInterface
{
public function show();
}
<?php
namespace App\AdapterPattern\TalentShow\Adapter;
use App\AdapterPattern\TalentShow\PianoPlayer;
use App\AdapterPattern\TalentShow\Contracts\ShowInterface;
class PianoPlayerAdapter implements ShowInterface
{
/**
* @var PianoPlayer
*/
protected $pianoPlayer;
public function __construct(PianoPlayer $pianoPlayer)
{
$this->pianoPlayer = $pianoPlayer;
}
public function show()
{
return $this->pianoPlayer->play();
}
}
透過這個轉接頭,
當我們請鋼琴表演者表演時,
他就會開始彈鋼琴。
<?php
namespace App\AdapterPattern\TalentShow\Adapter;
use App\AdapterPattern\TalentShow\Contracts\ShowInterface;
use App\AdapterPattern\TalentShow\JokeTeller;
class JokeTellerAdapter implements ShowInterface
{
/**
* @var JokeTeller
*/
protected $jokeTeller;
public function __construct(JokeTeller $jokeTeller)
{
$this->jokeTeller = $jokeTeller;
}
public function show()
{
return $this->jokeTeller->tell();
}
}
透過這個轉接頭,
當我們請笑話表演者表演時,
他就會開始講笑話。
<?php
namespace App\AdapterPattern\TalentShow;
use App\AdapterPattern\TalentShow\Adapter\PianoPlayerAdapter;
use App\AdapterPattern\TalentShow\Adapter\JokeTellerAdapter;
use App\AdapterPattern\TalentShow\Contracts\ShowInterface;
class Program
{
/**
* @var ShowInterface[]
*/
protected $performers = [];
/**
* @return array
*/
public function run()
{
$this->preparePerformers();
$result = [];
foreach ($this->performers as $performer) {
$result[] = $performer->show();
}
return $result;
}
private function preparePerformers()
{
$pianoPlayer = new PianoPlayer();
$this->performers[] = new PianoPlayerAdapter($pianoPlayer);
$jokeTeller = new JokeTeller();
$this->performers[] = new JokeTellerAdapter($jokeTeller);
}
}
透過各種實作表演介面的轉接頭,我們便能更好地管理表演項目了。
(比如:進退場的流程、項目的介紹等)
[單一職責原則]
我們將才藝類別與表演項目類別視作兩種不同的職責。
[開放封閉原則]
若我們需要在表演時,增加新的表演者,可以不修改原本才藝類別的程式碼。
只需新增一個對應的轉接頭。
[介面隔離原則]
才藝類別與表演項目類別實作的是兩個不同的接口。
透過轉接頭,讓原本接口不同的類別能夠介接。
[依賴反轉原則]
客戶端的程式碼依賴抽象的表演介面。
轉接頭實作抽象的表演介面。
最後附上類別圖:
(註:若不熟悉 UML 類別圖,可參考UML類別圖說明。)
ʕ •ᴥ•ʔ:除了上述包裹類別的方式外,轉接頭還能透過多重繼承的方式實現。
將來撰寫其他語言範例時,再來補充。