PHP設計模式之橋接模式橋接模式,在程序世界中,其實就是組合/聚合的代名詞。為什么這么說呢?熟悉面向對象的我們都知道繼承的好處,子類可以共享父類的很多屬性、功能。但是,繼承也會帶來一個問題,那就是嚴重的耦合性。父類的修改多少都會對子類產(chǎn)生影響,甚至一個方法或屬性的修改都有可能讓所有子類都去修改一遍。這樣就違背了開放封裝原則。而橋接就是為了解決這個問題,它強調(diào)的是用組合/聚合的方式來共享一些能用的方法。相信大家一定想到了php中的trait,如果你在工作中使用過這個特性,那么你就已經(jīng)用過橋接模式了! Gof類圖及解釋
GoF定義:將抽象部分與它的實現(xiàn)部分分離,使它們都可以獨立地變化。 GoF類圖
 代碼實現(xiàn)
interface Implementor { public function OperationImp(); }
class ConcreteImplementorA implements Implementor { public function OperationImp() { echo '具體實現(xiàn)A', PHP_EOL; } }
class ConcreteImplementorB implements Implementor { public function OperationImp() { echo '具體實現(xiàn)B', PHP_EOL; } }
我們先來定義實現(xiàn)接口以及它們具體的實現(xiàn),也就是真正要執(zhí)行的功能。就像是適配器模式中的Adaptee。 abstract class Abstraction { protected $imp; public function SetImplementor(Implementor $imp) { $this->imp = $imp; } abstract public function Operation(); }
class RefinedAbstraction extends Abstraction { public function Operation() { $this->imp->OperationImp(); } }
定義抽象類的接口,并維護一個對實現(xiàn)的引用。具體的抽象類的實現(xiàn)方法中,我們直接調(diào)用實現(xiàn)接口的真實操作方法。類似于適配器中的Adapter。 $impA = new ConcreteImplementorA(); $impB = new ConcreteImplementorB();
$ra = new RefinedAbstraction();
$ra->SetImplementor($impA); $ra->Operation();
$ra->SetImplementor($impB); $ra->Operation();
客戶端調(diào)用,我們的抽象類使用不用的實現(xiàn)類就可以讓操作方法變成多態(tài)的感覺。 在源碼解釋中,我們會發(fā)現(xiàn),這個模式和適配器模式非常相似。但是,適配器的目的是為了幫助兩個不太相關的類,讓它們能夠協(xié)同工作,實現(xiàn)中間轉換工作。而橋接則是為了讓方法的行為解除繼承耦合,方便地添加、修改,動態(tài)調(diào)用行為,讓抽象接口和實現(xiàn)部分可以獨立進行改變 讓抽象接口和實現(xiàn)部分可以獨立進行改變的意思是,只要維護了實現(xiàn)接口的引用,我們的實現(xiàn)接口的具體實現(xiàn)類可以是完全不同的類,里面有不同的功能,并且可以任意改變。讓實現(xiàn)來自己決定它自己是什么。 橋接模式的優(yōu)點:分享接口及其實現(xiàn)部分、提高可擴充性、實現(xiàn)細節(jié)對客戶透明 橋接模式最主要解決的問題就是繼承的不斷增長而帶來的緊耦合問題 組合與聚合:聚合是弱關系,A可以包含B,但B不是A的一部分;組合是強關系,A包含B,B也是A的一部分,整體和部分的關系
我們的手機有不同的型號,每個型號又要生產(chǎn)大致相同但不同的配件。比如X1手機殼、貼膜、耳機;X2的手機殼、貼膜、耳機等。受限于成本的問題,我們不會給每一個型號的手機都去生產(chǎn)完全不一樣的配套配件。而是去盡量使用外部通用的配件(Implementor),讓每一種型號的手機(Abstraction)去進行組合(Bridge),搭配售賣給消費者。這樣,才不至于讓我們的手機品牌太早的消耗完融資關門大吉。看來,做企業(yè)和學設計模式還真是有很多相關之處哦!! 完整代碼:https://github.com/zhangyue0503/designpatterns-php/blob/master/18.bridge/source/bridge.php 實例我們的短信發(fā)送也可以用橋接來實現(xiàn)。假設我們有很多的短信模板,然后搭配不同的短信提供商進行短信的發(fā)送。這時,我們就可以用橋接模式來形成各種不同的組合。 短信發(fā)送類圖
 完整源碼:https://github.com/zhangyue0503/designpatterns-php/blob/master/18.bridge/source/bridge-message.php <?php
interface MessageTemplate { public function GetTemplate(); }
class LoginMessage implements MessageTemplate { public function GetTemplate() { echo '您的登錄驗證碼是【AAA】,請不要泄露給他人【XXX公司】!', PHP_EOL; } } class RegisterMessage implements MessageTemplate { public function GetTemplate() { echo '您的注冊驗證碼是【BBB】,請不要泄露給他人【XXX公司】!', PHP_EOL; } } class FindPasswordMessage implements MessageTemplate { public function GetTemplate() { echo '您的找回密碼驗證碼是【CCC】,請不要泄露給他人【XXX公司】!', PHP_EOL; } }
abstract class MessageService { protected $template; public function SetTemplate($template) { $this->template = $template; } abstract public function Send(); }
class AliYunService extends MessageService { public function Send() { echo '阿里云開始發(fā)送短信:'; $this->template->GetTemplate(); } }
class JiGuangService extends MessageService { public function Send() { echo '極光開始發(fā)送短信:'; $this->template->GetTemplate(); } }
// 三個短信模板 $loginTemplate = new LoginMessage(); $registerTemplate = new RegisterMessage(); $findPwTemplate = new FindPasswordMessage();
// 兩個短信服務商 $aliYun = new AliYunService(); $jg = new JiGuangService();
// 隨意組合 // 極光發(fā)注冊短信 $jg->SetTemplate($registerTemplate); $jg->Send();
// 阿里云發(fā)登錄短信 $aliYun->SetTemplate($loginTemplate); $aliYun->Send();
// 阿里云發(fā)找回密碼短信 $aliYun->SetTemplate($findPwTemplate); $aliYun->Send();
// 極光發(fā)登錄短信 $jg->SetTemplate($loginTemplate); $jg->Send();
// ......
說明
這就是一種聚合模式。模板并不是短信發(fā)送的一部分,我們不使用模板直接發(fā)送也可以,它們沒有強關系 短信發(fā)送商的發(fā)送方法無需改變,只需要傳入不同的短信模板就可以實現(xiàn)各種模板的快速發(fā)送 在不確定是否一定是is-a的關系的情況下,更推薦用橋接模式這種組合/聚合形式的設計方法,如果確定當前的類關系是is-a,那么就不要猶豫的用繼承吧
下期看點上次提到過虛擬機軟件的橋接網(wǎng)絡模式,它的作用是類似于把物理主機虛擬為一個交換機,所有橋接設置的虛擬機連接到這個交換機的一個接口上,物理主機也同樣插在這個交換機當中,所以所有橋接下的網(wǎng)卡與網(wǎng)卡都是交換模式的,相互可以訪問而不干擾。其實和我們的設計模式很相似,將抽象對象看做是虛擬交換機,實現(xiàn)類就是虛擬機,通過對象的引用作為網(wǎng)線將它們連接在一起??粗唵蔚哪J降肷钊肜斫庖彩峭щy的吧?特別是它與其他模式很類似的時候。下回我們講的門面模式也是這樣,很好理解,但轉頭一想又會覺得跟其他一些模式很相似,所以,還是需要深入的理解才能更好的掌握這些模式,話不多說,下回見!
|