Before the dishes

The last chapter explained the bridge mode in the design pattern, I do not know whether I write you understand thoroughly. I left an Easter egg in the article (actually I am lazy), I don’t know if you noticed. Today, I’m going to give you an additional meal and talk about the implementation of what is considered the most classic bridge pattern: JDBC, and the tug-and-pull relationship between them.

The main course

Serving! Review the definition of the bridge pattern

1. Bridge mode definition

Version 1: Decouple the abstraction and implementation so that they can vary separately.

Version 2: A class has two (or more) dimensions that change independently. We combine them so that these two (or more) dimensions can be extended independently

See this definition, is not a little meaning to move the feeling, not a stranger, just one step can win “she”, so pay attention to my matchmaking wechat public number: Java Jinjintianlu (really shameless, advertising).

2. The definition of JDBC

JDBC, which stands for Java Database Connect, is a set of Java apis for executing SQL statements. The API allows applications to connect to a relational database and use SQL statements to query, update, and delete data in the database.

Note that JDBC here is an abstract set of apis, not a specific API

To review how we use JDBC, the above code.

Class.forName("com.mysql.jdbc.Driver");// Load and register the JDBC driver
String url = "jdbc:mysql://localhost:3306/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);
}
Copy the code

Class. ForName (” com.mysql.jdbc.driver “) requires the JVM to load the specified Driver Class.

// com.mysql.jdbc.driver Mysql Driver class
package com.mysql.cj.jdbc;

import java.sql.DriverManager;
import java.sql.SQLException;

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    public Driver(a) throws SQLException {}static {
        try {
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!"); }}}Copy the code

The code is simple, just a static block of code that does nothing but inject a mysql Driver object into the DriverManager class.

Now let’s take a look at what the DriverManager class does. The code for the DriverManager class is as follows. After registering the Driver implementation class (e.g., com.mysql.jdbc.driver) with DriverManager, all subsequent calls to the JDBC interface, Delegate to the specific Driver implementation class. The Driver implementation classes of different database vendors all implement the same interface (java.sql.Driver), and DriverManager and Driver implementation classes are combined together in a way of composition, which is also the reason why drivers can be switched flexibly.

public class DriverManager {

    // List of registered JDBC drivers
    private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();
    
    private DriverManager(a){}

    /**
     * Load the initial JDBC drivers by checking the System property
     * jdbc.properties and then use the {@code ServiceLoader} mechanism
     */
    static {
        loadInitialDrivers();
        println("JDBC DriverManager initialized");
    }

    @CallerSensitive
    public static Connection getConnection(String url, java.util.Properties info) throws SQLException {

        return (getConnection(url, info, Reflection.getCallerClass()));
    }
		
		 // Worker method called by the public getConnection() methods.
    private static Connection getConnection( String url, java.util.Properties info, Class
        caller) throws SQLException {
       / /......
        for(DriverInfo aDriver : registeredDrivers) { // Traverses all registered drivers
            // 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); // Call the specific Driver to connect
                    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");
    }
		
Copy the code

Let’s take a picture of what the JDBC framework looks like

Sun company abstracts out a set of database API interface, that is, defines the way to use the database in Java, and then each major database manufacturer implements its own database Driver according to the specifications formulated by Sun company. Now that abstraction and implementation are in place, Sun needs to figure out how to combine the two and still be flexible, and that’s where DriverManager comes in.

Now let’s go back to the definition of the bridge pattern “to decouple abstractions and implementations so that they can vary independently.” Understanding the definition of “abstract” and “implementation” is the key to understanding the bridging pattern. What is “abstraction” and what is “implementation” in JDBC design? JDBC abstraction out of that SET of API is abstract, different database service providers to achieve the Driver is implementation. So the abstraction in the bridge pattern does not mean an interface, but rather a set of apis designed for database operations. The implementation is not an interface, but a set of apis, such as connect, execute, etc. Finally, the abstraction and implementation are completely separated, allowing the two to work together in a way that combines this weak correlation, increasing flexibility and avoiding an exponential explosion of inheritance hierarchies. In fact, until the end of the call, DriverManager delegates to the specific Driver (connect, execute).

conclusion

The design pattern is like the foundation, but the bottom is important. I feel it is not easy to write good code. Learning design patterns is not about using a template to write code. We should pay more attention to the design ideas behind design patterns, which are designed to solve some problems and have withstood the test of history. As coders, we should take its essence and sublimate ourselves. Hope to progress together with you.

Please focus on

Finally, wave attention, wechat public number: Java Jinjintianlu, will update the relevant technical articles.