先说说桥接模式,桥接模式的特点是将实现和抽象进行分离,进行解耦。
将抽象与实现分离,使它们可以独立变化。它是用组合/聚合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。
桥接模式的基本结构
-
Abstraction — 抽象化角色:
定义抽象的接口,包含一个对实现化角色的引用 -
Refined Abstraciotn — 扩展抽象化角色:
抽象化角色的子类,实现父类中的业务方法,并通过组合/聚合关系调用实现化角色中的业务方法 -
Implementor — 实现化角色:
定义具体行为、具体特征的应用接口,供扩展抽象化角色使用 -
Concrete Implemetor — 具体实现化角色:
实现化角色的具体实现
实例一:模拟毛笔
现需要提供大中小3种型号的画笔,能够绘制5种不同颜色,如果使用蜡笔,我们需要准备3*5=15支蜡笔,也就是说必须准备15个具体的蜡笔类。而如果使用毛笔的话,只需要3种型号的毛笔,外加5个颜料盒,用3+5=8个类就可以实现15支蜡笔的功能。本实例使用桥接模式来模拟毛笔的使用过程。
image.png
JDBC中的桥接模式
JDBC中也分为两个维度的变化,一个是:Driver ,一个是Connection.
源码解析
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://<host>:<port>/<database>");
Class.forName()反射的三种方式之一,返回java.lang.Class对象,用于在程序运行时的某个时刻,由客户端调用,动态加载该类或该接口到当前线程中。
MySQL源码中:com.mysql.cj.jdbc.Driver类
com.mysql.cj.jdbc.Driver类仅包含一段静态代码,其中最关键的是静态代码段中的 DriverManager.registerDriver(new Driver()) ,它会在客户端调用Class.forName()方法加载com.mysql.cj.jdbc.Driver类的同时被执行,Driver类自身的一个实例被注册到DriverManager(即保存到DriverManager的静态字段registeredDrivers内)。
DriverManager类部分源码
public class DriverManager {
// List of registered JDBC drivers
private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();
private static volatile int loginTimeout = 0;
private static volatile java.io.PrintWriter logWriter = null;
private static volatile java.io.PrintStream logStream = null;
// Used in println() to synchronize logWriter
private final static Object logSync = new Object();
Class.forName()方法调用后,com.mysql.cj.jdbc.Driver类被加载,并执行static { } 静态代码段,将com.mysql.cj.jdbc.Driver类实例注册到DriverManager中。然后,客户端会调用DriverManager.getConnection()方法获取一个Connection数据库连接实例,该方法的部分源码如下:
for(DriverInfo aDriver : registeredDrivers) {
// If the caller does not have permission to load the driver then
// skip it.
if(isDriverAllowed(aDriver.driver, callerCL)) {
try {
println(" trying " + aDriver.driver.getClass().getName());
Connection con = aDriver.driver.connect(url, info);
if (con != null) {
// Success!
println("getConnection returning " + aDriver.driver.getClass().getName());
return (con);
}
} catch (SQLException ex) {
if (reason == null) {
reason = ex;
}
}
} else {
println(" skipping: " + aDriver.getClass().getName());
}
}
遍历registeredDrivers 集合,尝试每一个driver和数据库之间的连接,如果全部失败,就抛出异常提示连接失败。
Connection接口
DriverManager.getConnection()方法返回的Connection数据库连接实例根据不同的数据库有不同的实现。
这是变化的第二个维度。
image.png
网友评论