设计模式之美 - 桥接模式
设计模式之美目录:https://www.cnblogs.com/binarylei/p/8999236.html
桥接模式(Bridge):桥接模式不是很好理解,对于这个模式有两种不同的理解方式。但桥接模式并不常用,不是学习的重点。
- 在 GoF 的《设计模式》一书中,桥接模式被定义为:将抽象和实现解耦,让它们可以独立变化。
- 在其他资料和书籍中,还有另外一种更加简单的理解方式:一个类存在两个(或多个)独立变化的维度,我们通过组合的方式,让这两个(或多个)维度可以独立进行扩展。 解决多层继承结构中类无限膨胀的问题。
1. 桥接模式结构
1.1 经典理解方式
在 GoF 的《设计模式》一书中,桥接模式被定义为:将抽象和实现解耦,让它们可以独立变化。怎么理解这名话呢?我们以 JDBC 驱动为例,JDBC 驱动是桥接模式的经典应用。
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/db?user=root&password=123456";
Connection con = DriverManager.getConnection(url);
Statement stmt = con.createStatement();
String query = "select * from test";
ResultSet rs=stmt.executeQuery(query);
while(rs.next()) {
rs.getString(1);
rs.getInt(2);
}
如果我们想要把 MySQL 数据库换成 Oracle 数据库,只需要把第一行代码中的 com.mysql.jdbc.Driver 换成 oracle.jdbc.driver.OracleDriver 就可以了。当然,也有更灵活的实现方式,如 JDK 提供了 SPI 机制可以动态加载不同的实现类。OracleDriver 还是 MysqlDriver 都实现了 java.sql.Driver 接口。
说明: 桥接模式的定义是"将抽象和实现解耦,让它们可以独立变化"。那弄懂定义中 "抽象" 和 "实现" 两个概念,就是理解桥接模式的关键。那在 JDBC 这个例子中,什么是"抽象”?什么是"实现”呢?
- 抽象:本例中就是 JDBC 接口规范。注意,这里所说的 "抽象”,指的并非 "抽象类” 或 "接口”,而是跟具体的数据库无关的、被抽象出来的一套 "类库”,或者说的更直接一点是 "规范"。
- 实现:本例中就是具体的 Driver(com.mysql.jdbc.Driver)。注意,这里所说的 "实现",也并非指 "接口的实现类”,而是跟具体数据库相关的一套 "类库”。JDBC 和 Driver 独立开发,通过对象之间的组合关系,组装在一起。JDBC 的所有逻辑操作,最终都委托给 Driver 来执行。
1.2 组合代替继承
我们可以用多层继承实现下图的关系。
+电脑
+台式机(Desktop)
+联想台式机
+戴尔台式机
+神州台式机
+笔记本(Laptop)
+联想笔记本
+戴尔笔记本
+神州笔记本
+平板电脑(Pad)
+联想平板电脑
+戴尔平板电脑
+神州平板电脑
使用多层继承会形成"电脑 -> 机型 -> 品牌电脑”的继承关系,最终会有 "机型 * 品牌" 个类。随着机型和品牌的增加,类也会膨胀起来,怎么解决这个问题呢?
关键是"联想台式机”这个类既有机型也有品牌两个功能,可以考虑用组合代替继承的方式。
说明: 我们可以抽象出两个维度,品牌和类型两个接口,然后使用组合的方式减少类膨胀的问题,但本质还是面向接口编程,似乎和 GoF 的《设计模式》一书中 "将抽象和实现解耦,让它们可以独立变化" 也很类似。
2. 什么时候使用桥接模式
桥接模式本身并不常用。
桥接模式的优点
-
实现了抽象和实现部分的分离:理解抽象和实现,是理解桥接模式的核心。
-
更好的可扩展性:如扩展 MySQL、Oracle 的 Driver 驱动就非常容易。
-
可动态的切换实现:由于桥接模式实现了抽象和实现的分离,所以可以实现动态切换。
-
实现细节对客户端透明,可以对用户隐藏实现细节。
桥接模式的缺点
-
桥接模式的引入增加了系统的理解和设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计和编程。
-
桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围有一定的局限性。
每天用心记录一点点。内容也许不重要,但习惯很重要!