橋接模式(Bridge Pattern):
將抽象部分與它的實現部分分離,使它們都可以獨立地變化。它是一種對象結構型模式,又稱為柄體(Handle and Body)模式或介面(Interface)模式。
橋接模式包含如下角色:
Abstraction:抽象類別
RefinedAbstraction:擴充抽象類別
Implementor:實作類別介面
ConcreteImplementor:具體實作類別
UML圖:
理解橋接模式,重點需要理解如何將抽象化(Abstraction)與實現化(Implementation)脫耦,使得二者可以獨立地變化。
抽象化:抽象化就是忽略一些資訊,把不同的實體當作同樣的實體對待。在物件導向中,將對象的共同性質抽取出來形成類的過程即為抽象化的過程。
實現化:針對抽象化給出的具體實現,就是實現化,抽象化與實現化是一對互逆的概念,實現化產生的對象比抽象化更具體,是對抽象化事物的進一步具體化的產物。
脫耦:脫耦就是將抽象化和實現化之間的耦合解脫開,或者說是將它們之間的強關聯改換成弱關聯,將兩個角色之間的繼承關係改為關聯關係。橋接模式中的所謂脫耦,就是指在一個軟體系統的抽象化和實現化之間使用關聯關係(組合或者彙總關係)而不是繼承關係,從而使兩者可以相對獨立地變化,這就是橋接模式的用意。
優點:
分離抽象介面及其實現部分。
橋接模式有時類似於多繼承方案,但是多繼承方案違背了類的單一職責原則(即一個類只有一個變化的原因),複用性比較差,而且多繼承結構中類的個數非常龐大,橋接模式是比多繼承方案更好的解決方案。
橋接模式提高了系統的可擴充性,在兩個變化維度中任意擴充一個維度,都不需要修改原有系統。
實現細節對客戶透明,可以對使用者隱藏實現細節。
缺點:
橋接模式的引入會增加系統的理解與設計難度,由於彙總關聯關係建立在抽象層,要求開發人員針對抽象進
行設計與編程。 - 橋接模式要求正確識別出系統中兩個獨立變更維度,因此其使用範圍具有一定的局限性。
適用環境:
如果一個系統需要在構件的抽象化角色和具體化角色之間增加更多的靈活性,避免在兩個層次之間建立靜態繼承聯絡,通過橋接模式可以使它們在抽象層建立一個關聯關係。
抽象化角色和實現化角色可以以繼承的方式獨立擴充而互不影響,在程式運行時可以動態將一個抽象化子類的對象和一個實現化子類的對象進行組合,即系統需要對抽象化角色和實現化角色進行動態耦合。
一個類存在兩個獨立變更維度,且這兩個維度都需要進行擴充。
雖然在系統中使用繼承是沒有問題的,但是由於抽象化角色和具體化角色需要獨立變化,設計要求需要獨立管理這兩者。
對於那些不希望使用繼承或因為多層次繼承導致系統類別的個數急劇增加的系統,橋接模式尤為適用。
代碼實現:
imp->operationImp(); }}//修正抽象化角色,擴充抽象化角色,改變和修正父類對抽象化的定義。class RefinedAbstraction extends Abstraction { public function __construct(Implementor $imp) { $this->imp = $imp; } //操作方法在修正抽象化角色中的實現 public function operation() { echo 'RefinedAbstraction operation '; $this->imp->operationImp(); }} //實現化角色,給出實現化角色的介面,但不給出具體的實現。abstract class Implementor { //操作方法的實現化聲明 abstract public function operationImp();} //具體化角色A,給出實現化角色介面的具體實現class ConcreteImplementorA extends Implementor { //操作方法的實現化實現 public function operationImp() { echo 'Concrete implementor A operation
'; }} //具體化角色B 給出實現化角色介面的具體實現class ConcreteImplementorB extends Implementor { //操作方法的實現化實現 public function operationImp() { echo 'Concrete implementor B operation
'; }}
具體執行個體:
//實現各種作業系統都能播放MPEG,AVI,WMV格式的視頻//抽象類別,定義作業系統abstract class OperationSystem{ public $musicParren; function playMpeg(){ $this->musicParren->playMpeg(); } function playWmv(){ $this->musicParren->playWmv(); } function playAvi(){ $this->musicParren->playAvi(); }}//擴充抽象類別,定義Linux的播放模式class linux extends OperationSystem{ function __construct(MusicParren $musicParren){ $this->musicParren = $musicParren; }}//擴充抽象類別,定義Linux的播放模式class Windows extends OperationSystem{ function __construct(MusicParren $musicParren){ $this->musicParren = $musicParren; }}//擴充抽象類別,定義Unix的播放模式class Unix extends OperationSystem{ function __construct(MusicParren $musicParren){ $this->musicParren = $musicParren; }}//實作類別介面abstract class MusicParrenInterface{ abstract function playMpeg(); abstract function playWmv(); abstract function playAvi();}//具體實作類別class MusicParren extends MusicParrenInterface{ function playMpeg(){ echo "播放Mpeg格式的視頻"; } function playWmv(){ echo "播放Wmv格式的視頻"; } function playAvi(){ echo "播放Avi格式的視頻"; }}//測試$operationSystem = new Windows(new MusicParren());$operationSystem->playMpeg();$operationSystem->playAvi();