目录
前言:
桥接模式是我们平时接触比较少的一种设计模式,虽然从字面意思来看,这个设计模式比较好理解,其实不然,这是一个比较难理解的设计模式。接下来我主要用几个实际的例子来解释什么是桥接模式。
桥接模式的释义
桥接模式在GoF书籍中解释为:将抽象和实现解耦,让它们可以独立变化。这里的抽象并不是指抽象类,而是一种抽象概念。另一种解析为:一个类存在两个或多个独立变化的维度,我们通过组合的方式,让这两个或多个维度可以独立的进行扩展。通过组合关系来代替继承关系,避免继承层次指数级爆炸。解释到这里可能大家还是不太理解,可以结合下面的图来尝试理解。
这里的抽象和实现,其实就是两个逻辑概念,也就是两个可以独立变化的维度,然后两者通过组合的方式进行使用。接下来我们来看几个案例。
案例一:
JDBC 驱动是桥接模式的经典应用。我们先来看一下,如何利用 JDBC 驱动来查询数据库。具体的代码如下所示:
Class.forName("com.mysql.jdbc.Driver");//加载及注册JDBC驱动程序
String url = "jdbc:mysql://localhost:3306/sample_db?user=root&password=your_password";
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 就可以了。当然,也有更灵活的实现方式,我们可以把需要加载的 Driver 类写到配置文件中,当程序启动的时候,自动从配置文件中加载,这样在切换数据库的时候,我们都不需要修改代码,只需要修改配置文件就可以了。
桥接模式的定义是“将抽象和实现解耦,让它们可以独立变化”。那弄懂定义中“抽象”和“实现”两个 概念,就是理解桥接模式的关键。那在 JDBC 这个例子中,什么是“抽象”?什么是“实现”呢?
实际上,JDBC 本身就相当于“抽象”。注意,这里所说的“抽象”,指的并非“抽象类”或“接口”,而是跟具体的数据库无关的、被抽象出来的一套“类库”。具体的 Driver(比如,com.mysql.jdbc.Driver)就相当于“实现”。注意,这里所说的“实现”,也并非指“接口的实现类”,而是跟具体数据库相关的一套“类库”。JDBC 和 Driver 独立开发,通过对象之间的组合关系,组装在一起。JDBC 的所有逻辑操作,最终都委托给 Driver 来执行。
案例二
现在有两个纬度 Car 车 (奔驰、宝马、奥迪等)
Transmission 档位类型 (自动挡、手动挡、手自一体等)
按照继承的设计模式,Car是一个Abstract基类,假设有M个车品牌,N个档位一共要写M*N个类去描述所有车和档位的结合。
而当我们使用桥接模式的话,我首先new一个具体的Car(如奔驰),再new一个具体的Transmission(比如自动档)。然后奔驰.set(手动档)就可以了。
那么这种模式只有M+N个类就可以描述所有类型,这就是M*N的继承类爆炸简化成了M+N组合。
所以桥接模式解决的应该是继承爆炸问题。 可以看作是两个abstract组合在一起,独立去拓展,在运行之前将两个具体实现组合到一起。
一句话就是,桥接就是面向接口编程的集大成者。面向接口编程只是说在系统的某一个功能上将接口和实现解藕,而桥接是详细的分析系统功能,将各个独立的纬度都抽象出来,使用时按需组合。