聊聊Java设计模式-桥接模式

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 桥接(Bridge)模式是指将抽象部分与实现部分相分离,使它们都可以独立的发生变化。

桥接(Bridge)模式是指将抽象部分与实现部分相分离,使它们都可以独立的发生变化。

一、桥接模式介绍

我们知道,抽象部分一般与实现部分连接有两种方式:继承和实现。那么如何将其解耦分离,桥接模式提供一种方式,也就是将强关联转为弱关联,将继承转换为组合关系。如下图所示,取消两者的继承关系,改用组合关系:

image-20220330181522305

1.1 桥接模式的结构

我们可以看看桥接模式是怎么解耦,利用组合连接抽象和实现部分,如下所示:

image-20220330204226055

其结构中包含如下角色:

  • Abstraction:抽象化角色,定义抽象类,包含一个对实现化对象的引用(组合)
  • RefinedAbstraction:扩展抽象化角色,实现抽象化角色的子类,由此通过组合关系调用实现化角色中的业务方法
  • Implementor:实现化角色的接口,供扩展抽象化角色调用
  • ImplementorA、ImplementorB:实现化角色的具体实现

1.2 桥接模式的实现

我们可以根据上面的UML图实现对应的代码:

//客户端类
public class Client {
    public static void main(String[] args) {
        Implementor imple = new ImplementorA();
        Abstraction abs = new RefinedAbstraction(imple);
        abs.Operation();
    }
}
//实现化角色
interface Implementor {
    public void OperationImpl();
}
//具体的实现化角色
class ImplementorA implements Implementor {
    public void OperationImpl() {
        System.out.println("我是具体实现化角色A");
    }
}
class ImplementorB implements Implementor {
    public void OperationImpl() {
        System.out.println("我是具体实现化角色B");
    }
}
//抽象化角色
abstract class Abstraction {
    protected Implementor imple;
    
    protected Abstraction(Implementor imple) {
        this.imple = imple;
    }
    
    public abstract void Operation();
}
//扩展抽象化角色
class RefinedAbstraction extends Abstraction {
    protected RefinedAbstraction(Implementor imple) {
        super(imple);
    }
    
    public void Operation() {
        System.out.println("扩展抽象化角色被访问");
        imple.OperationImpl();
    }
}

实现结果:

扩展抽象化角色被访问
我是具体实现化角色A

二、桥接模式的应用场景

2.1 JDBC 驱动器

JDBC为所有的关系型数据库提供一个通用的标准,这就是一个桥接模式的典型应用。我们先回顾一下JDBC的使用,用JDBC连接MySQL数据库主要分为这样几步:

//1.加载MySQL驱动注入到DriverManager
Class.forName("com.mysql.cj.jdbc.Driver");
//2.提供JDBC连接的URL、用户名和密码
String url = "jdbc:mysql://localhost:3306/test_db?";
String username = "root";
String password = "root";
//3.创建数据库的连接
Connection connection = DriverManager.getConnection(url, username, password);
//4.创建statement实例
Statement statement = connection.createStatement();
//5.执行SQL语句
String query = "select * from test";  //查询语句,也可以换成CRUD的其他语句
ResultSet resultSet = statement.executeQuery(query);
//6.关闭连接对象
connection.close();

我们一步步来看,先看步骤1:

Class.forName("com.mysql.cj.jdbc.Driver");

查看对应的 com.mysql.cj.jdbc.Driver路径下的源码:

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!");
        }
    }
}

是通过静态方法调用registerDriver()方法来将MySQL驱动注入到DriverManagerregisterDriver()方法具体如下:

public static synchronized void registerDriver(java.sql.Driver driver)
    throws SQLException {
    //直接调用下面的同名静态方法
    registerDriver(driver, null);
}

public static synchronized void registerDriver(java.sql.Driver driver,DriverAction da)throws SQLException {
    /* registeredDrivers是一个list,用DriverInfo实例封装Driver */
    if(driver != null) {
        registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
    } else {
        // This is for compatibility with the original DriverManager
        throw new NullPointerException();
    }
    println("registerDriver: " + driver);

}

registeredDrivers静态变量其实是一个list:

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

DriverInfo类中封装了java.sql.Driver接口:

class DriverInfo {

    final Driver driver;
    DriverAction da;
    DriverInfo(Driver driver, DriverAction action) {
        this.driver = driver;
        da = action;
    }
    //...
}

再看步骤2、3,重点是步骤3

Connection connection = DriverManager.getConnection(url, username, password);

Connection接口是和特定数据库的连接会话,不同的数据库的连接会话都不相同:

public interface Connection  extends Wrapper, AutoCloseable {

    Statement createStatement() throws SQLException;
    //...
}

是通过DriverManager中的getConnection方法,从registeredDrivers进行选择对应数据库驱动下的连接实例:

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()));
}
// 实际上调用的是下面的静态方法getConnection
//  Worker method called by the public getConnection() methods.
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接口的具体实现部分,MySQL的连接是通过两层实现完成抽象部分的实现:

public class ConnectionImpl implements JdbcConnection, SessionEventListener, Serializable {
    private static final long serialVersionUID = 4009476458425101761L;
    private static final SQLPermission SET_NETWORK_TIMEOUT_PERM = new SQLPermission("setNetworkTimeout");
    //...
}
public interface JdbcConnection extends Connection, MysqlConnection, TransactionEventHandler {
    JdbcPropertySet getPropertySet();

    void changeUser(String var1, String var2) throws SQLException;
    //...
}

综上我们可以画出对应的类图:

image-20220330234125857

参考资料

https://jishuin.proginn.com/p/763bfbd68968

https://www.cnblogs.com/kuluo/p/13038076.html

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
22天前
|
设计模式 消息中间件 搜索推荐
Java 设计模式——观察者模式:从优衣库不使用新疆棉事件看系统的动态响应
【11月更文挑战第17天】观察者模式是一种行为设计模式,定义了一对多的依赖关系,使多个观察者对象能直接监听并响应某一主题对象的状态变化。本文介绍了观察者模式的基本概念、商业系统中的应用实例,如优衣库事件中各相关方的动态响应,以及模式的优势和实际系统设计中的应用建议,包括事件驱动架构和消息队列的使用。
|
1月前
|
设计模式 Java 数据库连接
Java编程中的设计模式:单例模式的深度剖析
【10月更文挑战第41天】本文深入探讨了Java中广泛使用的单例设计模式,旨在通过简明扼要的语言和实际示例,帮助读者理解其核心原理和应用。文章将介绍单例模式的重要性、实现方式以及在实际应用中如何优雅地处理多线程问题。
36 4
|
2月前
|
设计模式 Java 程序员
[Java]23种设计模式
本文介绍了设计模式的概念及其七大原则,强调了设计模式在提高代码重用性、可读性、可扩展性和可靠性方面的作用。文章还简要概述了23种设计模式,并提供了进一步学习的资源链接。
52 0
[Java]23种设计模式
|
2月前
|
设计模式 PHP 开发者
PHP中的设计模式:桥接模式的解析与应用
在软件开发的浩瀚海洋中,设计模式如同灯塔一般,为开发者们指引方向。本文将深入探讨PHP中的一种重要设计模式——桥接模式。桥接模式巧妙地将抽象与实现分离,通过封装一个抽象的接口,使得实现和抽象可以独立变化。本文将阐述桥接模式的定义、结构、优缺点及其应用场景,并通过具体的PHP示例代码展示如何在实际项目中灵活运用这一设计模式。让我们一起走进桥接模式的世界,感受它的魅力所在。
|
1月前
|
设计模式 JavaScript Java
Java设计模式:建造者模式详解
建造者模式是一种创建型设计模式,通过将复杂对象的构建过程与表示分离,使得相同的构建过程可以创建不同的表示。本文详细介绍了建造者模式的原理、背景、应用场景及实际Demo,帮助读者更好地理解和应用这一模式。
|
2月前
|
设计模式 监控 算法
Java设计模式梳理:行为型模式(策略,观察者等)
本文详细介绍了Java设计模式中的行为型模式,包括策略模式、观察者模式、责任链模式、模板方法模式和状态模式。通过具体示例代码,深入浅出地讲解了每种模式的应用场景与实现方式。例如,策略模式通过定义一系列算法让客户端在运行时选择所需算法;观察者模式则让多个观察者对象同时监听某一个主题对象,实现松耦合的消息传递机制。此外,还探讨了这些模式与实际开发中的联系,帮助读者更好地理解和应用设计模式,提升代码质量。
Java设计模式梳理:行为型模式(策略,观察者等)
|
3月前
|
存储 设计模式 安全
Java设计模式-备忘录模式(23)
Java设计模式-备忘录模式(23)
|
3月前
|
设计模式 自然语言处理 算法
PHP中的设计模式:桥接模式的深入探索与应用
在PHP开发中,理解并运用设计模式是提升代码质量与可维护性的关键。本文聚焦于桥接模式——一种结构型设计模式,它通过封装一个抽象的接口,将实现与抽象分离,从而使得它们可以独立变化。不同于传统摘要的概述式表述,本文将以故事化的情境引入,逐步解析桥接模式的精髓,通过PHP代码示例详细展示其在实际项目中的应用,旨在为读者提供一个既深刻又易于理解的学习体验。
29 1
|
3月前
|
设计模式 存储 缓存
Java设计模式 - 解释器模式(24)
Java设计模式 - 解释器模式(24)
|
3月前
|
设计模式 安全 Java
Java设计模式-迭代器模式(21)
Java设计模式-迭代器模式(21)
下一篇
DataWorks