先說說橋接模式,橋接模式的特點是將實現(xiàn)和抽象進行分離,進行解耦。
將抽象與實現(xiàn)分離,使它們可以獨立變化。它是用組合/聚合關(guān)系代替繼承關(guān)系來實現(xiàn),從而降低了抽象和實現(xiàn)這兩個可變維度的耦合度。
橋接模式的基本結(jié)構(gòu)
Abstraction — 抽象化角色:
定義抽象的接口,包含一個對實現(xiàn)化角色的引用Refined Abstraciotn — 擴展抽象化角色:
抽象化角色的子類,實現(xiàn)父類中的業(yè)務(wù)方法,并通過組合/聚合關(guān)系調(diào)用實現(xiàn)化角色中的業(yè)務(wù)方法Implementor — 實現(xiàn)化角色:
定義具體行為、具體特征的應(yīng)用接口,供擴展抽象化角色使用Concrete Implemetor — 具體實現(xiàn)化角色:
實現(xiàn)化角色的具體實現(xiàn)
實例一:模擬毛筆
現(xiàn)需要提供大中小3種型號的畫筆,能夠繪制5種不同顏色,如果使用蠟筆,我們需要準備3*5=15支蠟筆,也就是說必須準備15個具體的蠟筆類。而如果使用毛筆的話,只需要3種型號的毛筆,外加5個顏料盒,用3+5=8個類就可以實現(xiàn)15支蠟筆的功能。本實例使用橋接模式來模擬毛筆的使用過程。

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對象,用于在程序運行時的某個時刻,由客戶端調(diào)用,動態(tài)加載該類或該接口到當前線程中。
MySQL源碼中:com.mysql.cj.jdbc.Driver類
com.mysql.cj.jdbc.Driver類僅包含一段靜態(tài)代碼,其中最關(guān)鍵的是靜態(tài)代碼段中的 DriverManager.registerDriver(new Driver()) ,它會在客戶端調(diào)用Class.forName()方法加載com.mysql.cj.jdbc.Driver類的同時被執(zhí)行,Driver類自身的一個實例被注冊到DriverManager(即保存到DriverManager的靜態(tài)字段registeredDrivers內(nèi))。
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()方法調(diào)用后,com.mysql.cj.jdbc.Driver類被加載,并執(zhí)行static { } 靜態(tài)代碼段,將com.mysql.cj.jdbc.Driver類實例注冊到DriverManager中。然后,客戶端會調(diào)用DriverManager.getConnection()方法獲取一個Connection數(shù)據(jù)庫連接實例,該方法的部分源碼如下:
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和數(shù)據(jù)庫之間的連接,如果全部失敗,就拋出異常提示連接失敗。
Connection接口
DriverManager.getConnection()方法返回的Connection數(shù)據(jù)庫連接實例根據(jù)不同的數(shù)據(jù)庫有不同的實現(xiàn)。
這是變化的第二個維度。
