桥接模式,在编程世界里,其实就是组合/聚合的代名词。你为什么这么说?熟悉面向对象的人都知道继承的好处。子类可以共享父类的许多属性和功能。但是,继承也带来了一个问题,那就是严重的耦合。父类的修改会对子类产生影响,甚至一个方法或属性的修改都可能导致所有子类再次修改。这违反了开放封装的原则。桥接就是为了解决这个问题,它强调使用组合/聚合来共享一些可用的方法。相信大家肯定都想到了php中的trait。如果你在工作中使用过这个特性,那么你就已经使用过桥接模式了!Gof类图及说明GoF定义:将抽象部分与其实现分离,使它们都可以独立变化。GoF类图代码实现接口Implementor{publicfunctionOperationImp();}classConcreteImplementorAimplementsImplementor{publicfunctionOperationImp(){echo'具体实现A',PHP_EOL;}}classConcreteImplementorBimplementsImplementor{publicfunctionOperationImp(){echo'具体实现B',PHP_EOL;}}我们先来定义实现接口和它们的具体实现,也就是真正要执行的函数。这就像Adapter模式中的Adaptee。抽象类抽象{protected$imp;publicfunctionSetImplementor(Implementor$imp){$this->imp=$imp;}abstractpublicfunctionOperation();}classRefinedAbstractionextendsAbstraction{publicfunctionOperation(){$this->imp->OperationImp();}}定义抽象类的接口并维护对实现的引用。在具体抽象类的实现方法中,我们直接调用实现接口的真正操作方法。类似于适配器中的Adapter。$impA=newConcreteImplementorA();$impB=newConcreteImplementorB();$ra=newRefinedAbstraction();$ra->SetImplementor($impA);$ra->Operation();$ra->SetImplementor($impB);$ra->操作();客户端调用,我们的抽象类可以通过使用不同的实现类,使操作方法多态化。在源码解释中,我们会发现这种模式与适配器模式非常相似。但是,适配器的目的是帮助两个不太相关的类协同工作,实现中间转换工作。桥接是将方法的行为与继承解耦,方便地添加、修改、动态调用行为,使抽象接口和实现部分可以独立更改。抽象接口和实现部分可以独立改变。就是说只要维护了实现接口的引用,我们实现接口的具体实现类就可以是一个完全不同的类,功能不同,可以任意改变。让实施自己决定它是什么。桥接模式的优点:共享接口及其实现,提高可扩展性,实现细节对客户透明。桥接模式主要解决的问题是继承不断增长带来的紧耦合问题。组合与聚合:聚合是一种弱关系,A可以包含B,但B不属于A;组合是强关系,A包含B,B也是A的一部分,整体和部分的关系我们的手机有不同的型号,每个型号都要生产大致相同但不同的配件。比如X1手机壳、贴膜、耳机;X2手机壳、贴膜、耳机等。由于成本限制,我们不会为每个型号的手机生产完全不同的配套配件。而是尽量使用外部的通用配件(Implementor),让各个型号的手机(Abstraction)组合起来(Bridge),卖给消费者。这样我们的手机品牌就不会过早的用完融资而倒闭。看来做生意和学习设计模式真的有很大的关系啊!!完整代码: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.phptemplate=$template;}abstractpublicfunctionSend();}classAliYunServiceextendsMessageService{publicfunctionSend(){echo'阿里云开始发送短信:';$this->template->GetTemplate();}}classJiGuangServiceextendsMessageService{publicfunctionSend(){echo'JiGuang开始发送短信:';$this->template->GetTemplate();}}//三个短信模板$loginTemplate=newLoginMessage();$registerTemplate=newRegisterMessage();$findPwTemplate=newFindPasswordMessage();//两个短信服务商$aliYun=newAliYunService();$jg=newJiGuangService();//任意组合//极光发送注册短信$jg->SetTemplate($registerTemplate);$jg->Send();//阿里云发送登录短信$aliYun->SetTemplate($loginTemplate);$aliYun->Send();//阿里云发送密码重置短信$aliYun->SetTemplate($findPwTemplate);$aliYun->Send();//极光发送登录短信$jg->SetTemplate($loginTemplate);$jg->Send();//......说明这是一种聚合模式。模板不是SMS发送的一部分。我们可以不使用模板直接发送它们。他们没有牢固的关系。短信发送方的发送方式无需更改。只需要传入不同的短信模板就可以实现各种模板。在快速发送的情况下,如果不确定是否一定是is-a关系,更推荐使用桥接模式的组合/聚合设计方式。如果你确定当前的类关系是is-a,那就毫不犹豫的使用继承吧,看下一期。上次提到了虚拟机软件的桥接网络模式。其作用类似于将物理主机虚拟为交换机。所有有网桥设置的虚拟机都连接到这个交换机的一个接口上,物理主机也一样。插在这个交换机上,所以所有网卡和桥下的网卡都处于交换模式,可以互不干扰地访问。其实和我们的设计模式很像。抽象对象看成是虚拟交换机,实现类是虚拟机。它们通过对象引用作为网络电缆连接在一起。看着一个简单的模型,但试图理解它也很困难,对吧?特别是如果它与其他模式非常相似。下一次我们要讲的门面模型也是如此。它很容易理解,但仔细想想,你会觉得它和其他一些模型非常相似。因此,您仍然需要深入了解才能更好地掌握这些模型。话不多说,下面见!各媒体平台均可搜索【硬核项目经理】
