学习设计模式不光要学习设计模式的思想,还要去深入理解,为什么要用这个设计模式。
如何深入理解?读优秀的框架代码,看别人代码,了解它们的使用场景。 - - - 博主老师(感谢他)
本文先介绍了桥接模式的概念及简单实现。再介绍了JDBC中对桥接模式的实现。
桥接模式-概念、实现及JDBC中的桥接模式
1、概念
桥接模式(Bridge Pattern)也称桥梁模式
定义:将抽象部分与实现部分分离,使它们可以独立地进行定义。
多维度的变化类或者说多个树状类之间的耦合都可以用桥接模式来实现解耦。
似乎还有点模糊…直接看实现就能理解了。
2、实现
考虑这么一个例子:咖啡馆的咖啡分为:大杯加糖、大杯不加糖、小杯加糖、小杯不加糖
咖啡类
public abstract class Coffee {
protected CoffeeAdditives impl;
public Coffee(CoffeeAdditives impl) {
this.impl = impl;
}
public abstract void makeCoffee();
}
咖啡添加物
public abstract class CoffeeAdditives {
public abstract String addSomething();
}
大杯咖啡
public class LargeCoffee extends Coffee {
public LargeCoffee(CoffeeAdditives impl) {
super(impl);
}
@Override
public void makeCoffee() {
System.out.println("大杯的" + impl.addSomething() + "咖啡");
}
}
小杯咖啡
public class SmallCoffee extends Coffee {
public SmallCoffee(CoffeeAdditives impl) {
super(impl);
}
@Override
public void makeCoffee() {
System.out.println("小杯的" + impl.addSomething() + "咖啡");
}
}
添加剂:糖
public class Sugar extends CoffeeAdditives {
@Override
public String addSomething() {
return "加糖";
}
}
添加剂:无
public class Ordinary extends CoffeeAdditives {
@Override
public String addSomething() {
return "不加糖";
}
}
测试类
public static void main(String[] args) {
Ordinary ordinary = new Ordinary();
Sugar sugar = new Sugar();
Coffee largeCoffeeOrdinary = new LargeCoffee(ordinary);
largeCoffeeOrdinary.makeCoffee();
Coffee smallCoffeeOrdinary = new SmallCoffee(ordinary);
smallCoffeeOrdinary.makeCoffee();
Coffee largeCoffeeSugar = new LargeCoffee(sugar);
largeCoffeeSugar.makeCoffee();
Coffee smallCoffeeSugar = new SmallCoffee(sugar);
smallCoffeeSugar.makeCoffee();
}
输出
大杯的不加糖咖啡
小杯的不加糖咖啡
大杯的加糖咖啡
小杯的加糖咖啡
我们先定义了咖啡类,实现了大杯小杯。再定义了一个咖啡添加物类,实现了加糖和不加糖。其中,在咖啡中与添加物做了绑定。这里抽象部分是添加物,实现部分是咖啡。咖啡是被调用者,添加物是主动方。
3、JDBC中的桥接模式
我们知道jdbc只提出了一系列接口规范,具体的实现由数据库提供者去实现。所以,当我们在连接mysql的时候,需要添加jdbc-mysql.jar,在连接oracel的时候,需要添加ojdbc.jar(不确定jar名有没有写错,没在代码里用过oracel)。然后去载入驱动,再进行连接
// 使用
Class.forName("com.mysql.jdbc.Driver");
Connection conn= DriverManager.getConnection(url,user,password);
com.mysql.jdbc.Driver 源码
import java.sql.DriverManager;
import java.sql.SQLException;
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
public Driver() throws SQLException {
}
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
}
Class.forName会把类加载进来,执行类的静态方法(类加载的初始化阶段)。我们看到mysql Driver的static块,调用了java.sql.DriverManager的registerDriver方法。
public class DriverManager {
public static synchronized void registerDriver(java.sql.Driver driver) throws SQLException {
registerDriver(driver, null);
}
public static synchronized void registerDriver(java.sql.Driver driver, DriverAction da) throws SQLException {
/* Register the driver if it has not already been added to our list */
if(driver != null) {
registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
} else {
// This is for compatibility with the original DriverManager
throw new NullPointerException();
}
println("registerDriver: " + driver);
}
}
我们分析下,这里和桥接模式有什么关系。
回顾一下桥接模式的定义:将抽象部分与实现部分分离,使它们可以独立地进行定义。 为两个独立变化的维度设计两个独立的继承等级结构,并在抽象层建立一个抽象关联。
这里两个独立变化的维度:
- 数据库驱动
- 应用程序的数据库连接信息(可能是mysql,可能是oracel等)
对于应用程序而言,只要选用不同的驱动,就可以让程序操作不同的数据库,而无需更改应用程序,从而实现在不同的数据库上移植;
对于驱动程序而言,为数据库实现不同的驱动程序,并不会影响应用程序
4、思考
一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。可以考虑桥接模式。在设计系统的时候,尤其是对外开放的系统,一定要考虑这种变化可能带来的影响。以前没注意过这个jdbc的实现,粗浅得了解了下,真佩服啊…
设计模式的学习不要拘泥于局部代码,要从整体去把握。
[1] https://blog.csdn.net/paincupid/article/details/43614029