桥接模式详解和分析JDBC中的应用

🎯 设计模式专栏,持续更新中, 欢迎订阅:JAVA实现设计模式

🛠️ 希望小伙伴们一键三连,有问题私信都会回复,或者在评论区直接发言

桥接模式

文章目录

桥接模式(Bridge Pattern)是一种结构型设计模式,目的是将抽象部分与它的实现部分分离开来,使它们可以独立变化。这种模式通过组合的方式(而不是继承)将不同的维度分离,使代码更加灵活、易于扩展。

简单说法: 想象你有一个电视遥控器,遥控器负责打开/关闭电视、调节音量等操作。而不同品牌的电视(如索尼、三星)可能实现这些操作的方式不一样。桥接模式允许你在不修改遥控器代码的情况下,切换或扩展不同品牌的电视。遥控器和电视品牌之间使用接口桥接,使得它们可以独立变化。

桥接模式的四个核心组成:

  1. Abstraction(抽象部分):高层接口,定义抽象的操作,如遥控器的功能(打开、关闭、调音量等)。
  2. Refined Abstraction(扩展抽象部分):扩展自Abstraction,定义更具体的遥控器类型。
  3. Implementor(实现部分):具体实现接口,不同的实现类可以完成具体操作(不同品牌电视的功能实现)。
  4. Concrete Implementor(具体实现部分):Implementor的具体实现,如SonyTV和SamsungTV。

案例:电视与遥控器的桥接模式

你有一个通用的遥控器,可以操作不同品牌的电视,遥控器定义了on()off()setChannel()等功能,而每个品牌的电视实现这些功能的细节可能不同。通过桥接模式,我们将遥控器和电视品牌分离,便于扩展。

UML类图结构

java 复制代码
Abstraction                    Implementor
  RemoteControl   ---->    TV
   /     \                    /    \
Concrete    SonyRemote   SonyTV  SamsungTV
Abstraction                ConcreteImplementor

⚙️代码实现

Step 1: 实现 TV 接口 (Implementor)

java 复制代码
// TV接口定义基本操作
interface TV {
    void on();
    void off();
    void setChannel(int channel);
}

Step 2: 创建 SonyTVSamsungTV 类 (Concrete Implementor)

java 复制代码
// SonyTV 具体实现类
class SonyTV implements TV {
    @Override
    public void on() {
        System.out.println("Sony TV is now ON");
    }

    @Override
    public void off() {
        System.out.println("Sony TV is now OFF");
    }

    @Override
    public void setChannel(int channel) {
        System.out.println("Sony TV: Channel set to " + channel);
    }
}

// SamsungTV 具体实现类
class SamsungTV implements TV {
    @Override
    public void on() {
        System.out.println("Samsung TV is now ON");
    }

    @Override
    public void off() {
        System.out.println("Samsung TV is now OFF");
    }

    @Override
    public void setChannel(int channel) {
        System.out.println("Samsung TV: Channel set to " + channel);
    }
}

Step 3: 创建 RemoteControl 类 (Abstraction)

java 复制代码
// 遥控器抽象类,组合TV接口
abstract class RemoteControl {
    protected TV tv;

    // 通过构造方法传递TV对象,形成桥接
    public RemoteControl(TV tv) {
        this.tv = tv;
    }

    public abstract void on();

    public abstract void off();

    public abstract void setChannel(int channel);
}

Step 4: 创建 SonyRemoteControlSamsungRemoteControl (Refined Abstraction)

java 复制代码
// 扩展的具体遥控器类,使用不同的TV实现
class SonyRemoteControl extends RemoteControl {

    public SonyRemoteControl(TV tv) {
        super(tv);
    }

    @Override
    public void on() {
        System.out.println("Using Sony Remote Control:");
        tv.on();
    }

    @Override
    public void off() {
        System.out.println("Using Sony Remote Control:");
        tv.off();
    }

    @Override
    public void setChannel(int channel) {
        System.out.println("Using Sony Remote Control:");
        tv.setChannel(channel);
    }
}

class SamsungRemoteControl extends RemoteControl {

    public SamsungRemoteControl(TV tv) {
        super(tv);
    }

    @Override
    public void on() {
        System.out.println("Using Samsung Remote Control:");
        tv.on();
    }

    @Override
    public void off() {
        System.out.println("Using Samsung Remote Control:");
        tv.off();
    }

    @Override
    public void setChannel(int channel) {
        System.out.println("Using Samsung Remote Control:");
        tv.setChannel(channel);
    }
}

🌟 Main函数展示桥接模式的使用

java 复制代码
public class BridgePatternDemo {
    public static void main(String[] args) {
        // 创建不同品牌的电视
        TV sonyTV = new SonyTV();
        TV samsungTV = new SamsungTV();

        // 使用Sony Remote控制Sony TV
        RemoteControl sonyRemote = new SonyRemoteControl(sonyTV);
        sonyRemote.on();
        sonyRemote.setChannel(5);
        sonyRemote.off();

        System.out.println("-------------");

        // 使用Samsung Remote控制Samsung TV
        RemoteControl samsungRemote = new SamsungRemoteControl(samsungTV);
        samsungRemote.on();
        samsungRemote.setChannel(10);
        samsungRemote.off();
    }
}

运行结果:

java 复制代码
Using Sony Remote Control:
Sony TV is now ON
Using Sony Remote Control:
Sony TV: Channel set to 5
Using Sony Remote Control:
Sony TV is now OFF
-------------
Using Samsung Remote Control:
Samsung TV is now ON
Using Samsung Remote Control:
Samsung TV: Channel set to 10
Using Samsung Remote Control:
Samsung TV is now OFF

源码应用

JDBC中的桥接模式源码探索:

背景:

在Java的数据库连接(JDBC)中,JDBC API 提供了统一的数据库操作接口,而具体的数据库操作实现则由各数据库厂商的驱动(Driver)实现。这里,JDBC API 是抽象部分,而每个数据库驱动则是具体实现部分。

桥接模式分析:

  • Abstraction(抽象部分): java.sql.DriverManager 提供了一个统一的接口,用于注册不同数据库的驱动。
  • Implementor(实现部分): 各个数据库驱动(例如MySQL、PostgreSQL、Oracle等),分别通过实现 java.sql.Driver 接口来具体执行数据库连接操作。

桥接效果:

程序员只需基于统一的JDBC接口操作数据库,而无需关心底层数据库具体如何实现连接。通过桥接模式,可以轻松扩展或替换不同的数据库驱动,而不影响客户端代码。

代码使用示例:

java 复制代码
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "user", "password");

DriverManager 在内部会根据传入的 JDBC URL 查找合适的 Driver 来建立数据库连接,这样就将抽象的 Connection 操作与具体的数据库实现分离。

🌐 桥接模式的类图

java 复制代码
+-------------------------------------+                 +--------------------------------+
|          java.sql.Driver            |  <---- Bridge   |  Abstract representation      |
|-------------------------------------|                 | of how to connect to database |
| + connect()                         |                 | using different implementations|
| + acceptURL()                       |                 +--------------------------------+
| + other common methods              |          
+----------------+--------------------+     
                     ^
                     |       Implementor
                     |
      +-------------------------------+       +------------------------------------+
      |      com.mysql.cj.jdbc.Driver  |       |    org.postgresql.Driver           |
      +-------------------------------+       +------------------------------------+
      | + Implementation of connect()  |       |  + Implementation of connect()     |
      +-------------------------------+       +------------------------------------+

             ^                                         ^
             |                                         |
             +-------------------------------+         |
             |      java.sql.DriverManager   |          |
             +-------------------------------+         |
             |  + registerDriver(Driver d)    |         |
             |  + getConnection(String url)   |         |
             |  + other common methods        |         |
             +-------------------------------+         |
                                                        |
                                           +------------+-------------+
                                           |    java.sql.Connection   |
                                           +--------------------------+
                                           |  + createStatement()      |
                                           |  + close()                |
                                           +--------------------------+

⚙️ 关键源码解读:

1. Driver 接口(抽象部分,桥接接口)

java 复制代码
package java.sql;

import java.util.Properties;
import java.sql.SQLException;

public interface Driver {
    // 尝试建立数据库连接
    Connection connect(String url, Properties info) throws SQLException;

    // 判断Driver是否可以处理传入的URL
    boolean acceptsURL(String url) throws SQLException;

    // 获取驱动的相关属性信息
    DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException;

    // 获取驱动的主版本号
    int getMajorVersion();

    // 获取驱动的次版本号
    int getMinorVersion();

    // 检查驱动是否为JDBC规范的合规实现
    boolean jdbcCompliant();
}

在这个接口中,Driver定义了通用的行为,所有数据库驱动都需要实现这些方法,如 connect()acceptsURL()

2. DriverManager(抽象部分与实现部分的桥梁)

java 复制代码
package java.sql;

import java.util.Enumeration;
import java.util.Vector;
import java.sql.Driver;
import java.sql.SQLException;

public class DriverManager {

    // 注册驱动
    public static synchronized void registerDriver(java.sql.Driver driver) throws SQLException {
        registeredDrivers.addIfAbsent(new DriverInfo(driver));
    }

    // 通过指定URL连接数据库
    public static Connection getConnection(String url, String user, String password)
        throws SQLException {
        
        java.util.Properties info = new java.util.Properties();
        info.put("user", user);
        info.put("password", password);

        return getConnection(url, info);
    }

    // 具体的连接数据库逻辑
    public static Connection getConnection(String url, java.util.Properties info)
        throws SQLException {

        // 遍历已注册的驱动
        for (DriverInfo aDriver : registeredDrivers) {
            try {
                if (aDriver.driver.acceptsURL(url)) {
                    return aDriver.driver.connect(url, info); // 调用驱动的connect方法
                }
            } catch (SQLException e) {
                // 忽略异常,尝试下一个驱动
            }
        }
        throw new SQLException("No suitable driver found for " + url);
    }

    // 保持已注册驱动的信息
    private static final CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();

    static {
        // 内部静态代码块加载驱动
        loadInitialDrivers();
    }

    // 省略其他方法
}

解析:

  • DriverManager.registerDriver() 用于注册数据库驱动,开发者无需直接使用具体驱动类来注册。
  • DriverManager.getConnection() 是我们日常使用的API,内部通过调用已注册的 Driver 实现 connect() 方法来建立连接。

桥接模式应用: DriverManager 作为抽象的管理者 ,通过 Driver 接口的实现来具体连接到不同的数据库,真正实现了抽象和实现的分离。不同的数据库驱动(如MySQL、PostgreSQL等)是 Driver 接口的不同实现,开发者使用统一的 DriverManager.getConnection() 方法进行数据库操作,无需了解底层的实现。

3. com.mysql.cj.jdbc.Driver(具体实现部分)

java 复制代码
package com.mysql.cj.jdbc;

import java.sql.Driver;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

public class Driver implements java.sql.Driver {
    
    static {
        try {
            // 在类加载时自动注册MySQL驱动
            java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException e) {
            throw new RuntimeException("Failed to register MySQL driver.", e);
        }
    }

    @Override
    public Connection connect(String url, Properties info) throws SQLException {
        // 检查是否支持该URL
        if (!acceptsURL(url)) {
            return null;
        }

        // 创建与MySQL数据库的连接
        return new ConnectionImpl(host, port, dbName, user, password);
    }

    @Override
    public boolean acceptsURL(String url) {
        // 检查URL是否符合MySQL的格式
        return url.startsWith("jdbc:mysql:");
    }
    
    // 省略其他实现方法...
}

解析:

  • com.mysql.cj.jdbc.DriverDriver 接口的具体实现,通过桥接到 DriverManager,它实现了具体的连接MySQL数据库的逻辑。

  • acceptsURL() 方法判断传入的URL是否是MySQL的格式,connect() 方法则通过该URL与MySQL数据库建立连接。

JDBC桥接模式总结:

  • Abstraction(抽象部分) : DriverManager 是抽象部分,提供统一的API供开发者使用,它只负责管理和协调不同的 Driver 实现,而不关心具体实现细节。
  • Implementor(实现部分) : 各个数据库驱动实现了 Driver 接口,例如 com.mysql.cj.jdbc.Driverorg.postgresql.Driver,它们分别负责与具体的数据库进行交互。

桥接模式通过分离抽象和实现,使得JDBC API可以轻松支持多种不同的数据库,而开发者只需通过统一的 DriverManager.getConnection() 进行操作。不同数据库的连接实现细节被隐藏在各自的 Driver 实现类中,确保了系统的扩展性和维护性。

📜 总结:

桥接模式让我们能够将抽象部分与具体实现分离,在保持系统灵活的同时,允许独立扩展抽象和实现层次。在上面的例子中,RemoteControlTV 分离,使得你可以轻松扩展更多不同类型的遥控器或电视品牌,而无需修改已有代码。

桥接模式在JDK和各种框架中得到广泛应用,特别是在处理跨平台差异、解耦抽象和实现的场景中。通过桥接模式,能够保持系统的高扩展性和灵活性,便于维护和改进。无论是数据库操作、GUI绘制、日志框架还是视图解析,桥接模式都扮演着核心角色。

相关推荐
Arbori_262151 分钟前
获取oracle表大小
数据库·oracle
王强你强8 分钟前
MySQL 高级查询:JOIN、子查询、窗口函数
数据库·mysql
草巾冒小子9 分钟前
brew 安装mysql,启动,停止,重启
数据库·mysql
用户62799471826215 分钟前
南大通用GBase 8c分布式版本gha_ctl 命令-HI参数详解
数据库
斯汤雷24 分钟前
Matlab绘图案例,设置图片大小,坐标轴比例为黄金比
数据库·人工智能·算法·matlab·信息可视化
腥臭腐朽的日子熠熠生辉28 分钟前
解决maven失效问题(现象:maven中只有jdk的工具包,没有springboot的包)
java·spring boot·maven
ejinxian30 分钟前
Spring AI Alibaba 快速开发生成式 Java AI 应用
java·人工智能·spring
SQLplusDB31 分钟前
Oracle 23ai Vector Search 系列之3 集成嵌入生成模型(Embedding Model)到数据库示例,以及常见错误
数据库·oracle·embedding
杉之36 分钟前
SpringBlade 数据库字段的自动填充
java·笔记·学习·spring·tomcat
喝醉酒的小白1 小时前
SQL Server 可用性组自动种子设定失败问题
数据库