一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天,点击查看活动详情。
模式动机
如果我们有一个几何类 Shape,从它可以扩展出两个子类圆形 Circle 与正方形 Square,然后你希望在此之上进行扩展,使其包含颜色,所以就创建了红色 Red 类与蓝色 Blue 类,由于系统中有两个几何子类,所以你总共需要创建 2 x 2 个子类(RedCircle、BlueCircle、RedSquare、BlueSquare)才能覆盖所有组合。
假设你要新增一个三角形 Triangle 几何子类,再算上其红、蓝两种颜色,就需要在系统新增 2 个子类了;在此之上再添加一种绿色 Green 类,系统就需要新增 3 个子类,所有形状各一个。
显然,该方式违背了“开闭原则”,不利于系统扩展。
⭐问题根本在于我们试图同时在两个维度(形状、颜色)上进行扩展几何类。
我们不妨可以根据“合成复用原则”(尽量使用对象组合,而不是继承来达到复用的目的)来实现对系统的设计;具体来说,就是抽取其中一个维度并使之成为独立的类层次,然后使其作为初始类的成员对象即可。
将一个类层次转化为多个相关的类层次, 避免单个类层次的失控。
于是,形状类就可以将与颜色相关的工作委派给连入的颜色对象,而这种引用就成为了形状与颜色之间的桥梁。此后,新增颜色将不再需要修改形状的类层次了,反之亦然。
综上就是桥接模式的基本思想。
定义
桥接模式又称柄体模式或接口模式,它属于对象结构型模式。
桥接模式可将一个大类或一系列紧密相关的类拆分为抽象部分和实现部分两个独立的层次结构,使它们在开发时能独立地变化。
专业术语:抽象部分 & 实现部分
设计模式四人组在桥接模式中提出了抽象部分与实现部分两个术语,它们与编程语言中的接口或抽象类无关。
抽象部分是一些实体的高阶控制层,该层自身不完成任何具体工作,它需要将工作委派给实现部分层。
🔎以 ”模式动机“ 部分中所举的例子来说,它有两个独立方向可以扩展:
- 开发多个不同的形状
- 开发多个不同的颜色
通过桥接模式的定义,可以将其拆分为两个类层次结构:
- 抽象部分:形状
- 实现部分:颜色
⚡抽象对象控制着实体的形状,并将颜色相关的工作委派给连入的实现对象。
UML 类图
模式结构
桥接模式包含如下角色:
Abstraction:抽象部分提供高层控制逻辑,依赖于完成底层实际工作的实现对象。RefinedAbstraction:精确抽象实体提供具体的控制逻辑。Implementor:实现部分为所有具体实现声明通用接口,抽象部分仅能使用此处声明的接口与实现对象交互。ConcreteImplementor:具体实现类提供实现部分通用接口的具体逻辑。
更多实例
跨平台视频播放器
示例代码
Implementor.java
public interface Implementor {
void operationImpl();
}
Abstraction.java
public abstract class Abstraction {
protected Implementor impl;
public void setImpl(Implementor impl) {
this.impl = impl;
}
public abstract void operation();
}
RefinedAbstraction.java
public class RefinedAbstraction extends Abstraction {
@Override
public void operation() {
// TODO
impl.operationImpl();
// TODO
}
}
ConcreteImplementorA.java
public class ConcreteImplementorA implements Implementor {
@Override
public void operationImpl() {
// TODO
}
}
ConcreteImplementorB.java
public class ConcreteImplementorB implements Implementor {
@Override
public void operationImpl() {
// TODO
}
}
优缺点
✔桥接模式思想有点类似多继承。但多继承违背了类的“单一职责原则”(即一个类只能有一个变化的原因),复用性较差,而且多继承中类的个数庞大,桥接模式是一种优于多继承方案的解决方法。
✔桥接模式遵循”单一职责原则“,分离抽象接口及其实现部分:抽象部分专注于处理高层逻辑,实现部分处理具体细节;同时细节对客户透明,对用户隐藏实现细节。
✔桥接模式遵循了”开闭原则“。你可以新增抽象部分和实现部分,且它们之间不会相互影响。
❌桥接模式需要正确识别出系统中两个独立变化的维度,使用范围具有一定的局限性。
❌桥接模式的引入会增加系统的理解和设计难度,对高内聚的类使用该模式可能会让代码更加复杂。
适用场景
在以下情况推荐使用桥接模式:
(1)一个类存在两个独立变化的维度,且这两个维度都需要进行扩展或独立管理。
(2)对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。
「桥接模式」落地
Java Virtual Machine
Java 语言通过 Java 虚拟机实现了平台的无关性。
JDBC 驱动程序
🚩JDBC 驱动程序也是桥接模式的应用之一:使用 JDBC 驱动程序的应用系统就是抽象角色,而所使用的数据库是实现角色。
一个 JDBC 驱动程序可以动态地将一个特定类型的数据库与一个 Java 应用程序绑定在一起,从而实现抽象角色与实现角色的动态耦合。
JDBC 在「适配器模式」中也有其应用(上一篇文章有提及)
「桥接模式」&「适配器模式」的联调
桥接模式可以联合适配器模式一起使用:
- 桥接模式通常用于系统开发前期的设计,将程序各个部分独立开以便于开发;
- 适配器模式则通常在已有程序中使用,让相互不兼容的类能够很好地合作。
最后
❤️ 好的代码无需解释,关注「手撕设计模式」专栏,跟我一起学习设计模式,你的代码也能像诗一样优雅!
❤️ / END / 如果本文对你有帮助,点个「赞」支持下吧,你的支持就是我最大的动力!