这是我参与8月更文挑战的第14天,活动详情查看:8月更文挑战
首先祝大家七夕快乐!!!
今天我们一起来学习下原理非常简单,但是使用起来会有一定的难度的一种模式----桥接模式。多唠叨几句,我本月将会对java的设计模式精讲,欢迎点击头像,关注我的专栏,我会持续更新,加油!
...持续更新中
话不多说,进入正题
桥接模式
桥接模式,顾名思义,将不能组合到一起的,由该模式去进行绑定,我们在学习该模式的时候,重点要能跳出局部,多从整体结构上去思考。
官方定义:将抽象部分与它的实现部分分离,使它们都可以独立地变化。
注意这里:这里的抽象常常容易被理解为抽象类,并将实现理解为继承后的“派生类”,但是这样理解存在局限性,因为 GoF 的本意是想表达“从对象与对象间的关系去看,做抽象实体与抽象行为的分离”。
所以使用抽象实体和抽象行为来描述更为准确。
我们看下图清晰的表达下(该图来源于网络)
从该图中,我们可以看到桥接模式主要包含了以下四个关键角色。
-
抽象实体:定义的一种抽象分类。比如,电脑中的 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,代码部分到这里就结束了!!!
总结
桥接模式的本质是通过对一个对象进行实体与行为的分离,来将需要使用多层继承的场景转换为使用组合或聚合的方式,进而解耦对象间的强耦合关系,达到对象与对象之间的动态绑定的效果,提升代码结构的扩展性。
总体来说,桥接模式的使用场景非常灵活,侧重于实体和行为的分离,然后再基于这两个维度进行独立的演化。
其实我们运用桥接模式是为了以下几点:
第一个,为了灵活扩展代码结构
第二个,为了更好地解决跨平台兼容性问题
第三个,为了在运行时组合不同的组件
先说缺点,增加了维护成本,会导致性能下降,另外还会增加设计难度
优点:
-
符合开闭原则,提升代码复用性
-
提升了代码结构的演化灵活性
弦外之音
感谢你的阅读,如果你感觉学到了东西,麻烦您点赞,关注。
我已经将本章收录在专题里,点击下方专题,关注专栏,我会每天发表干货,本月我会持续输入设计模式。
加油! 我们下期再见!