前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >漫谈设计模式之桥接模式

漫谈设计模式之桥接模式

作者头像
孟君
发布2023-03-14 06:36:02
4490
发布2023-03-14 06:36:02
举报

今天,我们来分享结构型模式的另外一个成员:桥接模式

桥接模式是一种结构型设计模式,它将抽象部分和实现部分分离使得它们可以独立变化。桥接模式通过将抽象部分和实现部分分离,可以使得系统更加灵活,易于扩展和维护。

在介绍桥接模式之前,我们先来看一个使用继承在某些场景中可能遇到的问题:

当一个抽象可能有多个实现时,通常用继承来协调它们。抽象类定义对该抽象的接口,而具体的子类则有不同的方式加以实现。但是此方法有时候不够灵活。继承机制将抽象部分与它的实现部分固定在一起,使得难以对抽象部分和实现部分独立地进行修改、扩充和重用。

先来看一个示例,画不同颜色的图形的示例,如下采用继承的方式来做:

图片
图片

有什么问题?

1、如果新增加一种图形如,三角形Rectangle,需要做什么?

2、如果再增加一种颜色,还需要做什么?

从上图的继承方式我们可以发现,如果增加一个新的图形,如Rectangle,我们需要增加RedRectangle和BlueRectangle两个实现类。如果再次基础上,再增加一种颜色,如黄色,那么需要再增加3个子类,包括括YellowCircle、YellowSquare和YellowRectangle。

试想一下,如果后面还要增加新的图形、增加新的颜色将会导致类爆炸的情况,所有的子类的个数将等于图形的数量(A)乘 颜色的数量(B),即A*B个。这是不可接受的,

本文将介绍桥接模式,一起来看看桥接模式下会有什么变化。

桥接模式基本介绍

意图

将抽象部分与它的实现部分分离,使它们都可以独立的变化。

结构

桥接模式的基本结构如下:

图片
图片

这里涉及到的参与者有如下几种:

Abstract(抽象化)角色

抽象化给出的定义,并保存一个对实现化对象的引用。

RefinedAbstarct(修正抽象化)角色

扩展抽象化角色,改变和修正父类对抽象化的定义。

Implementor(实现化)角色

这个角色给出实现化角色的接口,但不给出具体的实现。必须指出的是,这个接口不一定和抽象化角色的接口定义相同,实际上,这两个接口可以非常不一样。实现化角色应用只给出底层操作,而抽象化角色应当只给出基于底层操作的更高一层的操作。

ConcreteImplementor(具体实现化)角色

这个角色给出实现化角色接口的具体实现。

桥接模式的示例

接下来,我们就使用上述示例,使用桥接模式来完成不同图形的绘制,使用不同颜色填充的功能。

Color.java(Implementor角色)

图片
图片

Red.java和Blue.java(ConcreteImplementor具体实现化角色 )

图片
图片
图片
图片

Shape.java(抽象化角色)

图片
图片

Cirlce.java和Square.java (具体实现)

图片
图片
图片
图片

Client.java(客户端)

图片
图片

输出结果:

代码语言:javascript
复制
绘制正方形- Shape circle= new Square(new Blue())
绘制正方形,使用蓝色填充绘制正方形,使用红色填充
绘制圆形- Shape circle= new Circle(new Blue())
绘制圆形,使用蓝色填充绘制圆形,使用红色填充

至此,一个图形采用不同颜色绘制的桥接模式示例就完成了。

再来看下本文前面提出的两个问题:

问题?

1、如果新增加一种图形如,三角形Rectangle,需要做什么?

2、如果再增加一种颜色,还需要做什么?

问题1:增加一个三角形图形Rentangle

图片
图片

绘制不同颜色的三角形:

图片
图片

输出

代码语言:javascript
复制
绘制三角形- Shape = new Rectangle(new Blue())
绘制三角形,使用蓝色填充绘制三角形,使用红色填充

我们可以看到,增加一个三角形图形类之后,其只需要增加一个子类即可,与实现化接口Color是解耦的,即不影响Color。

同样,我们再来看下第二个问题:

问题2:增加一个新的颜色Yellow

图片
图片

来看下原来的图形(Circle和Square)如何使用新增加Yellow颜色来绘制图形:

图片
图片

输出:

代码语言:javascript
复制
绘制正方形,使用黄色填充- Shape square= new Square(new Yellow())
绘制正方形,使用黄色填充绘制圆形,使用黄色填充- Shape circle= new Circle(new Yellow())
绘制三角形,使用黄色填充绘制三角形, 使用黄色填充- Shape rectangle = new Rectangle(new Yellow())
绘制三角形,使用黄色填充

可以看出,新增加一个具体的实现化类,对抽象的部分将不影响。

结论

无论增加新的具体化角色还是具体的抽象化,其只要增加一个子类即可。抽象和实现是解耦的,非常有利于扩展和维护。

小结

优点

1、分离接口及其实现部分。一个实现未必不变地绑定在一个接口上。抽象类的实现可以在运行时刻进行配置,一个对象甚至可以在运行时刻改变它的实现。将Abstraction和Implementor分离有助于降对实现部分编译时刻的依赖性,当改变一实现类时,并不需要重新编译Abstract类和它的客户程序。为了保证一个类库的不变版本之间的二进制兼容性,一定要有这个性质。

2、提高可扩充性。你可以独立地对Abstraction和Implementor层次结构进行扩充。

3、实现细节对客户透明。你可以对客户隐藏实现细节,例如共享Implementor对象以及相应的应用计数机制(如果有的话)。

缺点:

1、桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。

桥接模式之JDBC驱动

图片
图片

由于JDBC驱动器的存在,应用程序可以不依赖于数据库引擎的细节而独立地演化。同时数据库引擎也可以独立于应用系统的细节而独立演化。两个独立的等级结构如下图所示,左边是JDBC API的等级结构,右边是JDBC驱动的等级结构。应用程序是建立在JDBC API的基础之上的。应用系统通过委派与JDBC驱动相互作用,这是一个桥梁模式的例子。

图片
图片

适合场景

类的抽象以及它的实现都应该可以通过子类的方法加以扩充。这时桥接模式使你可以对不同的抽象接口以及它的实现部分进行组合并分别对它们进行扩充。

针对两个独立维度的变化,我们可以通过画坐标的方式来列出桥接模式的抽象和实现化。如,本文的示例,抽象化为图形(包括圆形、正方形、三角形),实现化为颜色填充(包括红色、蓝色、黄色 ... ... )。

又如,支付和支付实现,其抽象化可以是支付渠道(如支付宝、微信以及其他类型),其支付方式可以采用密码、指纹、刷脸。

图片
图片

其实,我们思考一下还能想到很多适合或者应用的桥接模式的场景,比如图表展示,我们可以采用ECharts、Three.js等来完成。又如系统间的通信,我们可以采用Restful API, RPC(grpc 、thrift等)以及消息队列MQ来做等等。

最后,再来想下,桥接模式和SPI有啥关系呢?

桥接模式 vs. SPI

桥接模式和SPI(Service Provider Interface)是两个不同的概念,但是它们之间有一些联系和相似之处。 桥接模式是一种结构型设计模式,它将抽象部分和实现部分分离,使得它们可以独立变化。桥接模式通过将抽象部分和实现部分分离,可以使得系统更加灵活,易于扩展和维护。 SPI(Service Provider Interface)是一种 Java 接口机制,用于实现模块之间的解耦。SPI 可以使得开发者将应用程序的扩展点与其实现分离开来,使得应用程序更加灵活,易于扩展和维护。 SPI 可以被看作是一种桥接模式的实现方式。在 SPI 中,服务提供者通过实现一个标准接口来提供服务,而应用程序通过查找和调用这些接口来使用这些服务。这样,应用程序就不需要知道服务提供者的具体实现,从而实现了抽象和实现的分离。

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 桥接模式基本介绍
  • 桥接模式的示例
  • 小结
相关产品与服务
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档