设计模式-桥接模式

news2024/9/27 9:24:30

桥接模式( Bridge Pattern )也称为桥梁模式、接口(Interfce)模式或柄体( Handle and Body)模 式,是将抽象部分与它的具体实现部分分离,使它们都可以独立地变化,属于结构型模式。

原文:Decouple an abstraction from its implementation so that the two can vary independently.
翻译:解锅抽象和实现,使得两者可以独立的变化。
也可以理解成:一个类存在两个(或多个)独立变化的维度,我们通过组合的方式,让这两个(或多个)维度可以独立进行扩展。

桥接模式主要目的是通过组合的方式建立两个类之间的联系,而不是继承。但又类似于多重继承方 案,但是多重继承方案往往违背了类得单一职责原则,其复用性比较差,桥接模式是比多重继承更好的 替代方案。桥接模式的核心在于解耦抽象和实现。
注:此处的抽象并不是指抽象类象接口这种商层概念,实现也不是继承或接口实现。抽象与实现其实指的是两种独立 变化的维度。

桥接模式的UML类图

具体代码:

public abstract class Abstraction {
    private final Implementor implementor;
    public Abstraction(Implementor implementor){
        this.implementor = implementor;
    }

    public void function(){
        implementor.implementation();
    }
}
复制代码
public class RefinedAbstraction extends Abstraction{
    public RefinedAbstraction(Implementor implementor) {
        super(implementor);
    }

    public void refinedFunction(){
        //子类扩展方法
        super.implementor.implementation();
    }

}
复制代码
public interface Implementor {
    void implementation();
}
复制代码
public class ConcreteImplementorA implements Implementor{
    @Override
    public void implementation() {
        System.out.println("ConcreteImplementorA");
    }
}
复制代码
public class ConcreteImplementorB implements Implementor{
    @Override
    public void implementation() {
        System.out.println("ConcreteImplementorB");
    }
}
复制代码
public class Test {
    public static void main(String[] args) {
        Implementor implementor = new ConcreteImplementorA();
        RefinedAbstraction refinedAbstraction = new RefinedAbstraction(implementor);
        refinedAbstraction.refinedFunction();
    }
}
复制代码

示例代码

举个例子,家用电器,有各种家用电器比如洗衣机、冰箱、空调,所有的家用电器又对应这自己的品牌,这就分离出来了两个维度一个是家用电器,还一个是品牌两个都能扩展,这里就很适合使用桥接模式 具体代码如下: 首先把家用电器抽象出来

public abstract class Product {
    protected ICompany company;


    public Product(ICompany company) {
        this.company = company;
    }

    public abstract void printProductInfo();
}
复制代码

具体实现

public class AirConditioner extends Product{
    public AirConditioner(ICompany company) {
        super(company);
    }
    @Override
    public void printProductInfo() {
        System.out.print(company.getName());
        System.out.print("公司---");
        System.out.println("空调");
    }
}
复制代码
public class Washer extends Product{
    public Washer(ICompany company) {
        super(company);
    }
    @Override
    public void printProductInfo() {
        System.out.print(company.getName());
        System.out.print("公司---");
        System.out.println("洗衣机");
    }
}
复制代码

然后就是公司的接口

public interface ICompany {
    String getName();
}
复制代码

具体实现:

public class Haier implements ICompany{
    @Override
    public String getName() {
        return "海尔";
    }
}
复制代码
public class Meidi implements ICompany{
    @Override
    public String getName() {
        return "美的";
    }
}
复制代码

最后使用方式:

public class Test {
    public static void main(String[] args) {
        Product product = new Washer(new Haier());
        Product product1 = new Washer(new Meidi());
        product.printProductInfo();
        product1.printProductInfo();
    }
}
复制代码

在源码中的应用

大家非常熟悉的 JDBC API,其中有一个Driver类就是桥接对象。我们都知道,我们在使用的时候 通过Class.forName()方法可以动态加载各个数据库厂商实现的 Driver 类。具体客户端应用代码如下, 以 MySQL的实现为例

Class.forName("com.mysql.jdbc.Driver");
Connection conn= DriverManager.getConnection("jdbc:mysql://1ocalhost:3306/test","root","root");
Statement stmt = conn.createStatement();
ResultSet resultSet = stmt.executeQuery("select *from table");
复制代码

先看Driver这个类

public interface Driver {
    Connection connect(String url, java.util.Properties info)
        throws SQLException;
    boolean acceptsURL(String url) throws SQLException;
    DriverPropertyInfo[] getPropertyInfo(String url, java.util.Properties info)
                         throws SQLException;
    int getMinorVersion();
    boolean jdbcCompliant();
    public Logger getParentLogger() throws SQLFeatureNotSupportedException;
}
复制代码

发现SDK提供的Driver 类是一个接口

mysql实现了这个接口 可以看到当加载Driver这个类的时候会执行

DriverManager.registerDriver(new Driver());
复制代码
public static void registerDriver(java.sql.Driver driver)
    throws SQLException {

    registerDriver(driver, null);
}
复制代码
public static void registerDriver(java.sql.Driver driver,
        DriverAction da)
    throws SQLException {

    /* Register the driver if it has not already been added to our list */
    if (driver != null) {
        registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
    } else {
        // This is for compatibility with the original DriverManager
        throw new NullPointerException();
    }

    println("registerDriver: " + driver);

}
复制代码

JDK底层是把mysql 的Driver的实例包装成了 DriverInfo对象.

接下来再看 getConnection方法

@CallerSensitive
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;
        if (callerCL == null || callerCL == ClassLoader.getPlatformClassLoader()) {
            callerCL = Thread.currentThread().getContextClassLoader();
        }

        if (url == null) {
            throw new SQLException("The url cannot be null", "08001");
        }

        println("DriverManager.getConnection("" + url + "")");

        ensureDriversInitialized();

        // 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.driver.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实现的 driver类返回的。

所以真实操作数据库的代码都是各个厂商根据自己数据库生成的,jdk只是统一了接口,所以切换数据库只需要切换驱动就行了。

这其中 DriverManager就相当于 Abstraction角色 Driver就是 Implementor角色,每个厂商对Driver的实现就是ConcreteImplementor角色

桥接模式优缺点

桥接(Bridge)模式的定义是:将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。
通过上面的讲解,我们能很好的感觉到桥接模式遵循了里氏替换原则和依赖倒置原则,最终实现了开闭原则,对修改关闭,对扩展开放。这里将桥接模式的优缺点总结如下:

优点:

  • 抽象与实现分离,扩展能力强
  • 符合开闭原则
  • 符合合成复用原则
  • 其实现细节对客户透明

缺点:

  • 增加了系统的理解与设计难度
  • 需要正确地识别系统中两个独立变化的维度

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/56264.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【图像分割】Unet-ConvLstm利用时序信息进行视频分割

文章目录0. 介绍1. ConvLstm1.1 Lstm1.2 ConvLstm0. 介绍 文章&#xff1a; Exploiting Temporality for Semi-Supervised Video Segmentation 代码&#xff1a; https://github.com/mhashas/Exploiting-Temporality-For-Semi-Supervised-Video-Segmentation 理解&#xff1a;…

塔望食业洞察丨大健康黄金赛道,低GI食品风起

随着“健康中国2030”国家战略进入到第二阶段&#xff0c;消费者在身心健康方面的提升诉求成为刚需 。在国家政策支持、技术发展的情况下&#xff0c;健康产业已经迎来前所未有的发展契机&#xff0c;健康产业百业兴盛。根据国家数据统计显示&#xff0c;2020年我国健康服务业规…

【加油站会员管理小程序】02创建数据源

我们上一篇介绍了加油站会员管理小程序的原型,本篇我们推导一下需要的数据源。 推导数据源的办法是要从页面上提炼需要存放的数据,在提炼的过程中要考虑表和表的拆分,主要是考虑主子关系。 在数据源设计中有关联关系和主子表的区分,关联关系是一种组成关系,比如学生和班…

扩散模型的启发和因果推论之数据增强

&#x1f37f;*★,*:.☆欢迎您/$:*.★* &#x1f37f; 正文 从因果中推导一种 数据增强的方法比如 使用相机采样的时候 随着相机的移动 采样的时间越短采样的数据越多 那么说名 数据量越大 这样虽然能达到更多数据量的目的但是如果输入是T1 输出是T2那么模型学习到的信息是确…

DSP篇--C6678功能调试系列之DDR3调试

目录 0、前言 1、硬件状态确认 2、DDR3调试 2.1 DDR3初始化 2.2 DDR3读写测试 2.3 DDR3 ECC&#xff08;略&#xff09; 0、前言 本来在写完《DSP篇--C6678 SPI BOOT详解及其优化实现》这篇文章后是不打算再去更新嵌入式相关的博文了&#xff08;主要是换行业了&#xff0…

一种用于环境声源的被动到达角(AoA)提取算法(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

G1D29-Roberta智能蜜罐环境

一、Roberta &#xff08;一&#xff09;特点 对bert的一点点改进啦 1、动态遮掩 2、FULL-SENTENCE without NSP loss 3、Large mini-batch 4、A larger Byte-Pair Encoding &#xff08;二&#xff09;关于BERT中的NSP和MLM 参考&#xff1a;https://blog.csdn.net/qq_436…

创建一个web项目

servlet 概念: 运行在服务端的程序&#xff0c;是一个接口&#xff0c;定义了java类被浏览器访问到(tomcat识别)的规则 tomcat会读取web.xml文件中的配置 创建一个web项目 目录说明: 1.src&#xff1a;自动编译.java文件的目录 依赖的jdk版本 依赖的tomcat版本 build: 用来…

JAVAWEB_实验三 Servlet 相关技术

文章目录Servlet 基础一、 实验目的二、 实验要求三、 实验内容过滤器一、 实验目的二、 实验原理三、 实验内容试简述过滤器有哪些功能&#xff1f;实现一个查询天气的 web 程序Servlet 基础 一、 实验目的 理解 Servlet 的工作原理&#xff0c;掌握 Servlet 的应用开发方法…

Kanzi:项目实例:大灯Lamp界面设计

概述&#xff1a; 大灯页面&#xff08;LampPage&#xff09;主要包括&#xff1a;OFFbtn、Autobtn、ParkLampbtn、HeadLampbtn 这个四个 状态。我们就先简单的分析下。 1: LampPageController 页面 这个controller页面维护两个页面&#xff08;FirstPage和SecondPage&#…

LeetCode刷题复盘笔记—一文搞懂0 - 1背包之474. 一和零问题(动态规划系列第十篇)

今日主要总结一下动态规划0-1背包的一道题目&#xff0c;474. 一和零问题 题目&#xff1a;416. 分割等和子集 Leetcode题目地址 题目描述&#xff1a; 给你一个二进制字符串数组 strs 和两个整数 m 和 n 。 请你找出并返回 strs 的最大子集的长度&#xff0c;该子集中 最多…

【servelt原理_9_servlet应用___】

servlet应用*** 1.request对象 是当客户端向服务器端发送请求时&#xff0c;服务器为本次请求创建request对象&#xff0c;并在调用Servlet的service方法时&#xff0c;将该对象传递给service方法。Request对象中封装了客户端发送过来的所有的请求数据。 ①:doGet()方法接收r…

Maven详细总结

参考博客&#xff1a;https://blog.csdn.net/xiaodi2016/article/details/121341063 ※注意&#xff1a; 我们自己的Maven工程必须执行安装操作才会进入仓库。安装的命令是&#xff1a;mvn install 任何一个Maven工程会根据坐标到本地仓库中去查找它所依赖的jar包…

临近过年无情被裁,我面试大厂的这几个月…

秋招接近尾声&#xff0c;即将远去的“金九银十”今年也变成了“铜九铁十”。 大厂不断缩招&#xff0c;不容忽视的疫情影响&#xff0c;加上不断攀升的毕业生人数&#xff0c;各种需要应对的现实问题让整个求职季难上加难。 在这个异常残酷的求职季&#xff0c;很多人的困惑…

【intent-filter】AndroidManifest中<intent-filter>标签的 部分作用

这里写自定义目录标题AndroidManifest.xmlIntent-filter 标签Intent-filter 标签中的常用元素Intent-filter 标签的作用Intent对象Intent显式启动活动窗口Intent隐式启动&#xff08;重要&#xff09;AndroidManifest.xml AndroidManifest.xml是安卓开发中主配置文件&#xff…

【负荷预测】基于蚂蚁优化算法的BP神经网络在负荷预测中的应用研究(Matlab完整代码实现)

目录 0 知识回顾 1 ACO-BP算法 2 ACO-BP算法基本思路 3 具体步骤 4 Matlab代码实现 5 运行结果 6 参考文献 7 写在最后 0 知识回顾 智能优化算法—蚁群算法&#xff08;Python实现&#xff09; 1 ACO-BP算法 传统的BP神经网络训练采用的是误差反向传播学习算法,它的…

2023最新SSM计算机毕业设计选题大全(附源码+LW)之java高校教室申请管理系统yf80k

计算机毕业设计的编程真的不会, 应该怎么办啊, 平时学了3年都没学懂&#xff0c;然而还有一个月就要答辩了&#xff0c;一点东西都没做出来&#xff0c;不知道该怎么办了&#xff1f;好迷茫&#xff0c;如果毕不到业怎么办, 有没有快速的学习方法 毕设毕设&#xff0c;最终的是…

【C++面向对象程序设计】CH7 输入输出流

目录 一、前言 二、标准输出流 1.流对象 &#xff08;1&#xff09;cout流对象 &#xff08;2&#xff09;cerr流对象 &#xff08;3&#xff09;【例7.1】编写程序&#xff0c;从键盘输入a&#xff0c;b&#xff0c;c的值求解一元二次方程。如果a0或判别式的值<0&…

拾壹博客拆解改造,页面元素替换(二)

页面元素替换 首先要做的当然是换成自己风格的站名和内容啦。 1、网站配置 跟踪前端代码后发现配置是来自后端接口&#xff0c;想着既然入库了&#xff0c;那应该有对应的管理页面吧&#xff0c;果然找到了&#xff0c;就是…演示账号不允许操作&#xff01;那么接下来要干的…

stm32f767的fft

仅作自己笔记用 1&#xff0c;FFT函数调用基础知识 采样得到的数字信号&#xff0c;就可以做FFT变换了。N个采样点&#xff0c;经过FFT之后&#xff0c;就可以得到N个点的FFT结果。为了方便进行FFT运算&#xff0c;通常N取2的整数次方。 假设采样频率为Fs&#xff0c;信号频率…