PHP設計模式之橋接模式

橋接模式,在程序世界中,其實就是組合/聚合的代名詞。爲何這麼說呢?熟悉面向對象的咱們都知道繼承的好處,子類能夠共享父類的不少屬性、功能。可是,繼承也會帶來一個問題,那就是嚴重的耦合性。父類的修改多少都會對子類產生影響,甚至一個方法或屬性的修改都有可能讓全部子類都去修改一遍。這樣就違背了開放封裝原則。而橋接就是爲了解決這個問題,它強調的是用組合/聚合的方式來共享一些能用的方法。相信你們必定想到了php中的trait,若是你在工做中使用過這個特性,那麼你就已經用過橋接模式了!php

Gof類圖及解釋

GoF定義:將抽象部分與它的實現部分分離,使它們均可以獨立地變化。git

GoF類圖github

橋接模式

代碼實現設計模式

interface Implementor
{
    public function OperationImp();
}

class ConcreteImplementorA implements Implementor
{
    public function OperationImp()
    {
        echo '具體實現A', PHP_EOL;
    }
}

class ConcreteImplementorB implements Implementor
{
    public function OperationImp()
    {
        echo '具體實現B', PHP_EOL;
    }
}

咱們先來定義實現接口以及它們具體的實現,也就是真正要執行的功能。就像是適配器模式中的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();
    }
}

定義抽象類的接口,並維護一個對實現的引用。具體的抽象類的實現方法中,咱們直接調用實現接口的真實操做方法。相似於適配器中的Adapter。網絡

$impA = new ConcreteImplementorA();
$impB = new ConcreteImplementorB();

$ra = new RefinedAbstraction();

$ra->SetImplementor($impA);
$ra->Operation();

$ra->SetImplementor($impB);
$ra->Operation();

客戶端調用,咱們的抽象類使用不用的實現類就可讓操做方法變成多態的感受。學習

  • 在源碼解釋中,咱們會發現,這個模式和適配器模式很是類似。可是,適配器的目的是爲了幫助兩個不太相關的類,讓它們可以協同工做,實現中間轉換工做。而橋接則是爲了讓方法的行爲解除繼承耦合,方便地添加、修改,動態調用行爲,讓抽象接口和實現部分能夠獨立進行改變
  • 讓抽象接口和實現部分能夠獨立進行改變的意思是,只要維護了實現接口的引用,咱們的實現接口的具體實現類能夠是徹底不一樣的類,裏面有不一樣的功能,而且能夠任意改變。讓實現來本身決定它本身是什麼。
  • 橋接模式的優勢:分享接口及其實現部分、提升可擴充性、實現細節對客戶透明
  • 橋接模式最主要解決的問題就是繼承的不斷增加而帶來的緊耦合問題
  • 組合與聚合:聚合是弱關係,A能夠包含B,但B不是A的一部分;組合是強關係,A包含B,B也是A的一部分,總體和部分的關係

咱們的手機有不一樣的型號,每一個型號又要生產大體相同但不一樣的配件。好比X1手機殼、貼膜、耳機;X2的手機殼、貼膜、耳機等。受限於成本的問題,咱們不會給每個型號的手機都去生產徹底不同的配套配件。而是去儘可能使用外部通用的配件(Implementor),讓每一種型號的手機(Abstraction)去進行組合(Bridge),搭配售賣給消費者。這樣,纔不至於讓咱們的手機品牌太早的消耗完融資關門大吉。看來,作企業和學設計模式還真是有不少相關之處哦!!this

完整代碼:https://github.com/zhangyue0503/designpatterns-php/blob/master/18.bridge/source/bridge.php阿里雲

實例

咱們的短信發送也能夠用橋接來實現。假設咱們有不少的短信模板,而後搭配不一樣的短信提供商進行短信的發送。這時,咱們就能夠用橋接模式來造成各類不一樣的組合。設計

短信發送類圖

短信發送功能橋接模式版

完整源碼: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 '阿里雲開始發送短信:';
        $this->template->GetTemplate();
    }
}

class JiGuangService extends MessageService
{
    public function Send()
    {
        echo '極光開始發送短信:';
        $this->template->GetTemplate();
    }
}

// 三個短信模板
$loginTemplate = new LoginMessage();
$registerTemplate = new RegisterMessage();
$findPwTemplate = new FindPasswordMessage();

// 兩個短信服務商
$aliYun = new AliYunService();
$jg = new JiGuangService();

// 隨意組合
// 極光發註冊短信
$jg->SetTemplate($registerTemplate);
$jg->Send();

// 阿里雲發登陸短信
$aliYun->SetTemplate($loginTemplate);
$aliYun->Send();

// 阿里雲發找回密碼短信
$aliYun->SetTemplate($findPwTemplate);
$aliYun->Send();

// 極光發登陸短信
$jg->SetTemplate($loginTemplate);
$jg->Send();

// ......

說明

  • 這就是一種聚合模式。模板並非短信發送的一部分,咱們不使用模板直接發送也能夠,它們沒有強關係
  • 短信發送商的發送方法無需改變,只須要傳入不一樣的短信模板就能夠實現各類模板的快速發送
  • 在不肯定是否必定是is-a的關係的狀況下,更推薦用橋接模式這種組合/聚合形式的設計方法,若是肯定當前的類關係是is-a,那麼就不要猶豫的用繼承吧

下期看點

上次提到過虛擬機軟件的橋接網絡模式,它的做用是相似於把物理主機虛擬爲一個交換機,全部橋接設置的虛擬機鏈接到這個交換機的一個接口上,物理主機也一樣插在這個交換機當中,因此全部橋接下的網卡與網卡都是交換模式的,相互能夠訪問而不干擾。其實和咱們的設計模式很類似,將抽象對象看作是虛擬交換機,實現類就是虛擬機,經過對象的引用做爲網線將它們鏈接在一塊兒。看着簡單的模式但想深刻理解也是挺困難的吧?特別是它與其餘模式很相似的時候。下回咱們講的門面模式也是這樣,很好理解,但轉頭一想又會以爲跟其餘一些模式很類似,因此,仍是須要深刻的理解才能更好的掌握這些模式,話很少說,下回見!

關注公衆號:【硬核項目經理】獲取最新文章

添加微信/QQ好友:【xiaoyuezigonggong/149844827】免費得PHP、項目管理學習資料

知乎、公衆號、抖音、頭條搜索【硬核項目經理】

B站ID:482780532

相關文章
相關標籤/搜索