java桥接模式 | 抽象与不同实现的绑定

264 阅读6分钟

桥接模式.png

这是我参与8月更文挑战的第14天,活动详情查看:8月更文挑战

首先祝大家七夕快乐!!!

image.png

今天我们一起来学习下原理非常简单,但是使用起来会有一定的难度的一种模式----桥接模式。多唠叨几句,我本月将会对java的设计模式精讲,欢迎点击头像,关注我的专栏,我会持续更新,加油!

设计模式之单例模式

设计模式之工厂模式

设计模式之建造者模式

设计模式之代理模式

设计模式之访问者模式

设计模式之适配器模式

设计模式之命令者模式

java状态模式 | 随时随地监控状态改变

java观察者模式 | 如何通知事物的变化

java备忘录模式 | 如何记录历史信息

java迭代器模式模式 | 如何对各个元素进行访问

java享元模式 | 如何共享对象

java解释器模式 | 自定义规则实现逻辑

...持续更新中

话不多说,进入正题

桥接模式

桥接模式,顾名思义,将不能组合到一起的,由该模式去进行绑定,我们在学习该模式的时候,重点要能跳出局部,多从整体结构上去思考。

官方定义:将抽象部分与它的实现部分分离,使它们都可以独立地变化。

注意这里:这里的抽象常常容易被理解为抽象类,并将实现理解为继承后的“派生类”,但是这样理解存在局限性,因为 GoF 的本意是想表达“从对象与对象间的关系去看,做抽象实体与抽象行为的分离”。

所以使用抽象实体和抽象行为来描述更为准确。

我们看下图清晰的表达下(该图来源于网络)

image.png

从该图中,我们可以看到桥接模式主要包含了以下四个关键角色。

  • 抽象实体:定义的一种抽象分类。比如,电脑中的 CPU、内存、摄像头、显示屏等。

  • 具体实体:继承抽象实体的子类实体。比如,Intel i7 CPU、三星内存、徕卡摄像头、京东方显示屏幕等。

  • 抽象行为:定义抽象实体中具备的多种行为。比如,CPU 逻辑运算、内存读写存储、摄像头拍照、屏幕显示图像等。

  • 具体行为:实现抽象行为的具体算法。比如,Intel 使用 X64 架构实现 CPU 逻辑运算,Mac M1 芯片使用 ARM 架构实现 CPU 逻辑运算,等等

我们可以看到,我们从大范围往下分析。所以重点要能跳出局部,多从整体结构上去思考。彼此分离又密切联系。

我个人看来,桥接模式原理的核心是抽象与抽象之间的分离,这样分离的好处就在于,具体的实现类依赖抽象而不是依赖具体

我们接下来用一种场景结合代码展示下

代码展示

比如,在支付场景中,我们支持微信、支付宝、各大银行的支付组件等。这里的统一协议是收款、支付、扣款,而组件就是微信、支付宝等(把支付类型理解为组件)。将行为和协议区分开来。下面我们看下代码

我们首先创建一个抽象实体类 Pay,它包含了两个抽象行为:支付(charge)和扣款(cutCharge)

//抽象接口Pay
public interface Pay {
    //支付行为(传过去一个订单进行支付,返回拉起支付所需信息)
    JSONObject charge(String orderId);
    
    //扣款
    boolean cutCharge(int money);
}

然后,我们再建立一个具体实体类 PayImpl,其中包含了抽象行为类 PayExcutor(支付执行器),实现了抽象行为 charge 和 cutCharge

//具体实体类
public class PayImpl implements Pay {
    private PayExcutor excutor = null;
    public PayImpl(PayExcutor excutor) {
        this.excutor = excutor;
    }
    @Override
    public JSONObject charge(String orderId) {
        return excutor.uploadFile(path);
    }
    @Override
    public boolean cutCharge(int money) {
        return excutor.checkFile(object);
    }
}

//执行器
public interface PayExcutor {
    JSONObject charge(String orderId);
    boolean cutCharge(int money);
}

接下来,我们用微信和支付宝进行不同的支付规则执行器,进行相应的行为 ,具体代码如下所示:

//微信
public class WxExcutor implements PayExcutor {
    @Override
    public JSONObject charge(String orderId) {
        return null;
    }
    @Override
    public boolean cutCharge(int money) {
        return true;
    }
}

//支付宝
public class AliExcutor implements PayExcutor {
     @Override
    public JSONObject charge(String orderId) {
        return null;
    }
    @Override
    public boolean cutCharge(int money) {
        return true;
    }
}

从上面的代码中,你会发现:通过将支付执行器和支付行为进行分离,就能实现实体和行为的灵活演化。比如,当你想要实现一个新的支付类型执行器时,比如我们用农行支付,建行支付,都可以加入相应的具体实现类,然后建立支付执行器,接着再分别实现各种不同的支付执行器。如果你还想要在执行器里加入新的行为,比如退款等,这时平台上的执行器并不需要调用“退款”这个接口。

这样就做到了实体和行为的解耦,极大地提升了代码的扩展性。

思考下:在实现抽象行为时,我们可以使用以前介绍过的的适配器模式来扩展功能,也可以使用后面即将会学到的门面模式来扩展更多外部的服务功能。

OK,代码部分到这里就结束了!!!

总结

桥接模式的本质是通过对一个对象进行实体与行为的分离,来将需要使用多层继承的场景转换为使用组合或聚合的方式,进而解耦对象间的强耦合关系,达到对象与对象之间的动态绑定的效果,提升代码结构的扩展性。

总体来说,桥接模式的使用场景非常灵活,侧重于实体和行为的分离,然后再基于这两个维度进行独立的演化。

其实我们运用桥接模式是为了以下几点:

第一个,为了灵活扩展代码结构

第二个,为了更好地解决跨平台兼容性问题

第三个,为了在运行时组合不同的组件

image.png

先说缺点,增加了维护成本,会导致性能下降,另外还会增加设计难度

优点:

  • 符合开闭原则,提升代码复用性

  • 提升了代码结构的演化灵活性

弦外之音

感谢你的阅读,如果你感觉学到了东西,麻烦您点赞,关注。

我已经将本章收录在专题里,点击下方专题,关注专栏,我会每天发表干货,本月我会持续输入设计模式。

加油! 我们下期再见!