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

相关文章
相关标签/搜索