前言: 在我們還沒學習框架之前,肯定都學過JDBC。百度百科對JDBC是這樣介紹的【JDBC(Java DataBase Connectivity,java資料庫連接)是一種用於執行SQL語句的Java API,可以為多種關係資料庫提供統一訪問,它由一組用Java語言編寫的類和介面組成。JDBC提供 ...
前言:
在我們還沒學習框架之前,肯定都學過JDBC。百度百科對JDBC是這樣介紹的【JDBC(Java DataBase Connectivity,java資料庫連接)是一種用於執行SQL語句的Java API,可以為多種關係資料庫提供統一訪問,它由一組用Java語言編寫的類和介面組成。JDBC提供了一種基準,據此可以構建更高級的工具和介面,使資料庫開發人員能夠編寫資料庫應用程式,同時,JDBC也是個商標名。】通過JDBC我們可以完成Java對關係型資料庫的SQL操作。下麵我們介紹的這種模式是JDBC中使用的設計模式。
一、定義
將抽象部分與它的具體實現部分分離,使他們都可以獨立地變化。是通過組合方式建立兩個類之間的聯繫,而不是繼承
二、適用場景
1、抽象和具體實現之間增加更多靈活性
使用橋接模式可以避免在這兩個之間建立靜態的繼承關係,而是去建立組合關係。
2、一個類存在兩個(或多個)獨立變化的維度,且這兩個維度需要獨立進行擴展
對於橋接模式可以這樣理解,橋接就像一座橋,可以用來連接兩個不同地方,這兩個地方自由發展,中間的貿易是通過一座橋來連接。
3、不希望使用繼承,或者是由於多層繼承導致系統類的個數劇增
同第一點理解
三、JDBC中的橋接模式
首先我們弄清楚橋接模式中需要什麼角色:
1、實現類介面
2、抽象類
3、實現介面類
4、繼承抽象類
我們來看一下大概的圖是怎麼樣的
從圖中我們能很清楚的看到抽象類和介面之間是通過組合方式來關聯,這樣關聯有什麼好處呢?抽象類下麵可以自行發展自己的子類,並且介面類也可以自己發展子類。兩者之間互不影響。這正是我們上面所說的兩個維度獨立擴展。不要以為客戶端只能調用使用抽象類,而是介面下麵的實現類可以放入抽象類的子類中進行操作。大致瞭解完之後,JDBC中又是怎麼實現橋接模式的呢?
我們對Driver介面一定不陌生。如果從橋接模式來看,Driver就是一個介面,下麵可以有MySQL的Driver,Oracle的Driver,這些就可以當做實現介面類。那麼我們現在來看看MySQL中的Driver類
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!"); } } }
特別簡短的代碼,其實只調用了DriverManager中的registerDriver方法來註冊驅動。當驅動註冊完成後,我們就會開始調用DriverManager中的getConnection方法了
public class DriverManager { public static Connection getConnection(String url, String user, String password) throws SQLException { java.util.Properties info = new java.util.Properties(); if (user != null) { info.put("user", user); } if (password != null) { info.put("password", password); } return (getConnection(url, info, Reflection.getCallerClass())); } private static Connection getConnection( String url, java.util.Properties info, Class<?> caller) throws SQLException { /* * When callerCl is null, we should check the application's * (which is invoking this class indirectly) * classloader, so that the JDBC driver class outside rt.jar * can be loaded from here. */ ClassLoader callerCL = caller != null ? caller.getClassLoader() : null; synchronized(DriverManager.class) { // synchronize loading of the correct classloader. if (callerCL == null) { callerCL = Thread.currentThread().getContextClassLoader(); } } if(url == null) { throw new SQLException("The url cannot be null", "08001"); } println("DriverManager.getConnection(\"" + url + "\")"); // Walk through the loaded registeredDrivers attempting to make a connection. // Remember the first exception that gets raised so we can reraise it. SQLException reason = null; 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()); } } // if we got here nobody could connect. if (reason != null) { println("getConnection failed: " + reason); throw reason; } println("getConnection: no suitable driver found for "+ url); throw new SQLException("No suitable driver found for "+ url, "08001"); } } }
上面是簡化的代碼,可以看到需要返回的是Connection對象。在Java中通過Connection提供給各個資料庫一樣的操作介面,這裡的Connection可以看作抽象類。可以說我們用來操作不同資料庫的方法都是相同的,不過MySQL有自己的ConnectionImpl類,同樣Oracle也有對應的實現類。這裡Driver和Connection之間是通過DriverManager類進行橋接的,不是像我們上面說的那樣用組合關係來進行橋接。
四、總結
橋接模式其實特別好理解,只需要看一眼上面的UML類圖,也許你就知道橋接模式的使用方法。JDBC這裡使用橋接模式可以讓Driver和Connection下麵的類根據不同資料庫來實現不同的發展。就像我們適用場景中的第二點。當然正如我們標題所說的結合著JDK源碼來看設計模式。也許看完這篇博客你有自己的理解JDBC這裡為什麼要用橋接模式。