【设计模式系列】餐补:桥接模式与JDBC的故事

前菜

上篇讲解了设计模式中的桥接模式,不知道我写的大家是否读懂悟透了。我在文章中留了一个彩蛋(其实就是我懒),不知道大家是否发现了。 今天,我就来给大家加加餐,聊一聊被认为最经典桥接模式的实现:JDBC,她们两之间拉拉扯扯的关系。

主菜

上菜了!回顾下桥接模式的定义

1.桥接模式定义

版本一:将抽象和实现解耦,让他们能各自变化。

版本二:一个类存在两个(或多个)独立变化的维度,我们通过组合的方式,让这两个(或多个)维度可以独立进行扩展

看到这个定义,是不是有点儿意动的感觉了,不是陌生人了,差一步就可以拿下“她”了,所以关注下我的红娘微信公众号吧:java精进天路(真不要脸,打广告)。

2.JDBC的定义

JDBC的全称是Java数据库连接(Java Database connect),它是一套用于执行SQL语句的Java API。应用程序可通过这套API连接到关系数据库,并使用SQL语句来完成对数据库中数据的查询、更新和删除等操作。

注意一下,这里的JDBC是一套抽象的API,而非特定的一个API

回顾下我们是怎么使用JDBC的,上代码。

Class.forName("com.mysql.jdbc.Driver");//加载及注册JDBC驱动程序
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);
}
复制代码

分析下上面的这段代码,Class.forName("com.mysql.jdbc.Driver")要求JVM加载指定的Driver类,我们来看看这个Driver类中到底是啥?

//com.mysql.jdbc.Driver mysql驱动类
package com.mysql.cj.jdbc;

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!");
        }
    }
}
复制代码

代码很简单,就是一个静态代码块,干了啥呢,就只是向DriverManager类中注入了一个mysql的Driver对象。

现在,我们再来看一下,DriverManager 类是干什么用的。具体的DriverManager类的部分代码如下,当我们把具体的 Driver 实现类(比如,com.mysql.jdbc.Driver)注册到DriverManager之后,后续所有对JDBC接口的调用,都会委派到对具体的Driver实现类来执行。而不同数据库厂商的Driver 实现类都实现了相同的接口(java.sql.Driver ),并且DriverManager和Driver实现类之间是通过组合的方式结合在一起的,这也是可以灵活切换 Driver 的原因。

public class DriverManager {

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

    /**
     * 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) { //遍历所有已经注册进来的Driver
            // 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); //调用具体的Driver去连接
                    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");
    }
		
复制代码

我们来张图了解下JDBC的使用框架大概是个什么样子

file

Sun公司抽象出了一套操作数据库的API接口,也就是说定义了java中使用数据库的方式,然后各大数据库厂商根据Sun公司制定的规范去实现自己的数据库驱动Driver。到这里抽象和实现都已经有了,Sun公司就需要考虑如何让两者组合起来使用,而且还能具备灵活性,这就是DriverManager的工作了。

现在我们再回头看看桥接模式的定义“将抽象和实现解耦,让它们可以独立变化”。那弄懂定义中“抽象”和“实现”两个概念,就是理解桥接模式的关键。那在JDBC的设计中,什么是“抽象”,什么是“实现”呢?JDBC抽象出来的那套API就是抽象,不同数据库服务商实现的Driver就是实现。所以桥接模式中的抽象并不是指一个接口,它可能是设计出来的一套跟数据库操作相关的API。而具体的实现也不是一个接口,也可能是一套API,就像Driver中的connect,execute等方法。最后抽象和实现彻底分开,以组合这种弱关联的方式让两者相互合作,增强灵活性,避免继承层次的指数级爆炸。其实调用到最后,DriverManager都是委托具体的Driver干活的(connect,execute)

结束语

设计模式就想是地基,底层却很重要。能写出好代码,我觉的很不容易,学习设计模式,并不是要套模版写代码,我们更多关注的应该是设计模式背后的设计思想,他们都是为了解决一些问题而设计出来的,都是经受住历史的考验的经验。同为代码人,我们应该做到取其精华,升华自己。 望与诸君共同进步。

求关注

最后求波关注,微信公众号:java精进天路,会同步更新相关技术文章。

Supongo que te gusta

Origin juejin.im/post/7066448550506266661
Recomendado
Clasificación