桥接模式 Bridge Pattern:处理多维度变化

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 主要内容有:该模式的介绍,包括:引子、意图(大白话解释)类图、时序图(理论规范)该模式的代码示例:熟悉该模式的代码长什么样子该模式的优缺点:模式不是万金油,不可以滥用模式该模式的应用案例:了解它在哪些重要的源码中被使用


前言



主要内容有:

  • 该模式的介绍,包括:
  • 引子、意图(大白话解释)
  • 类图、时序图(理论规范)
  • 该模式的代码示例:熟悉该模式的代码长什么样子
  • 该模式的优缺点:模式不是万金油,不可以滥用模式
  • 该模式的应用案例:了解它在哪些重要的源码中被使用


结构型——桥接模式 Bridge Pattern



引子


桥接模式是软件设计模式中最复杂的模式之一,它把事物对象和其具体行为、具体特征分离开来,使它们可以各自独立的变化。

如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度?这就要使用Bridge模式。

就拿汽车在路上行驶的来说。即有小汽车又有公共汽车,它们都不但能在市区中的公路上行驶,也能在高速公路上行驶。这你会发现,对于交通工具(汽车)有不同的类型,然而它们所行驶的环境(路)也在变化,在软件系统中就要适应两个方面的变化?怎样实现才能应对这种变化呢?


定义

将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。


类图

如果看不懂UML类图,可以先粗略浏览下该图,想深入了解的话,可以继续谷歌,深入学习:

桥接模式类图:

  • Abstraction:抽象类
  • RefinedAbstraction:扩充抽象类
  • Implementor:实现类接口
  • ConcreteImplementor:具体实现类


时序图

时序图(Sequence Diagram)是显示对象之间交互的图,这些对象是按时间顺序排列的。时序图中显示的是参与交互的对象及其对象之间消息交互的顺序。

我们可以大致浏览下时序图,如果感兴趣的小伙伴可以去深究一下:


代码实现

代码参考:

segmentfault.com/a/119000002…

我们有不同的银行(工行,农行,建行),也有不同的卡(储蓄卡,信用卡),我们将银行和卡进行抽象。

/**
 * 银行抽象类
 */
public abstract class Bank {
    protected Account account;
    public Bank(Account account) {
        this.account = account;
    }
    /**
     * 不限制方法名,但因为委派所以起的一样
     * 不要自己都实现了,要尽量把行为委托给组合的类
     * @return
     */
    abstract Account openAccount();
}
/**
 * 农业银行实现类
 */
public class ABCBank extends Bank {
    public ABCBank (Account account) {
        super(account);
    }
    @Override
    Account openAccount() {
        System.out.println("打开中国农业银行账号");
        account.openAccount();
        return account;
    }
}
/**
 * 工商银行实现类
 */
public class ICBCBank extends Bank {
    public ICBCBank(Account account) {
        super(account);
    }
    @Override
    Account openAccount() {
        System.out.println("打开中国工商银行账号");
        account.openAccount();
        return account;
    }
}
/**
 * 银行账号, 桥的实现接口
 */
public interface Account {
    /**
     * 打开账号
     * @return
     */
    Account openAccount();
    /**
     * 查看账号类型
     */
    void showAccountType();
}
/**
 * 定期账户实现类
 */
public class DepositAccount implements Account {
    @Override
    public DepositAccount openAccount() {
        System.out.println("打开定期账号");
        return new DepositAccount();
    }
    @Override
    public void showAccountType() {
        System.out.println("这是定期账号");
    }
}
/**
 * 活期账户实现类
 */
public class SavingAccount implements Account {
    @Override
    public SavingAccount openAccount() {
        System.out.println("打开活期账号");
        return new SavingAccount();
    }
    @Override
    public void showAccountType() {
        System.out.println("这是活期账号");
    }
}
复制代码

客户端调用:

public class Test {
    public static void main(String[] args) {
        Bank icbcBank = new ICBCBank(new DepositAccount());
        Account icbcAccount = icbcBank.openAccount();
        icbcAccount.showAccountType();
        Bank abcBank = new ABCBank(new SavingAccount());
        Account abcAccount = abcBank.openAccount();
        abcAccount.showAccountType();
    }
}
复制代码

调用结果:

打开中国工商银行账号
打开定期账号
这是定期账号
打开中国农业银行账号
打开活期账号
这是活期账号
复制代码


使用场景举例


JDBC数据库访问接口API正是经典的桥接模式实现:

通常使用JDBC连接数据库时,会使用如下代码:

Class.forName("数据库类驱动器");
Connection conn = DriverManager.getConnection("数据库url", "用户名", "密码");
//.................
复制代码

JDBC为不同的数据库操作提供了相同的接口,但是JDBC本身并没有针对每种数据库提供一套具体实现代码,而是通过接口java.sql.Driver的connect方法连接到了不同的数据库实现。

如连接mysql数据库:

package com.mysql.jdbc;
public class NonRegisteringDriver implements java.sql.Driver //对java.sql.Driver接口提供了实现
{
public Connection connect(String url, Properties info)
        throws SQLException
    {
        //实现
    }
    //其他方法
}
复制代码

Java在连接MySQL时需要使用mysql-connector-java.jar,mysql-connector-java.jar包提供了对MySQL数据库操作的具体实现,并通过接口Driver连接到了JDBC统一的api。


优缺点

优点

  • 优秀的扩展能力。
  • 实现细节对客户透明。

缺点

桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。


总结



桥接模式与装饰模式的区别:

这两个模式在一定程度上都是为了减少子类的数目,避免出现复杂的继承关系。但是它们解决的方法却各有不同

  • 装饰模式:装饰模式把子类中比基类中多出来的部分放到单独的类里面,以适应新功能增加的需要,当我们把描述新功能的类封装到基类的对象里面时,就得到了所需要的子类对象,这些描述新功能的类通过组合可以实现很多的功能组合 .
  • 桥接模式:桥接模式则把原来的基类的实现化细节抽象出来,在构造到一个实现化的结构中,然后再把原来的基类改造成一个抽象化的等级结构,这样就可以实现系统在多个维度上的独立变化 。


桥接模式和适配器模式的区别

共同点:

桥接和适配器都是让两个东西配合工作

不同点:

  • 适配器:改变已有的两个接口,让他们相容。所以说,如果你拿到两个已有模块,想让他们同时工作,那么你使用的适配器。
  • 桥接模式:分离抽象化和实现,使两者的接口可以不同,目的是分离,但是并不修改任何接口的具体内容。如果你还什么都没有,但是想分开实现,那么桥接是一个选择。


参考



相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
相关文章
|
网络架构 网络协议
uni-app监听页面滚动
uni-app监听页面滚动
803 0
|
前端开发 Java 数据安全/隐私保护
用户登录前后端开发(一个简单完整的小项目)——SpringBoot与session验证(带前后端源码)全方位全流程超详细教程
文章通过一个简单的SpringBoot项目,详细介绍了前后端如何实现用户登录功能,包括前端登录页面的创建、后端登录逻辑的处理、使用session验证用户身份以及获取已登录用户信息的方法。
1580 2
用户登录前后端开发(一个简单完整的小项目)——SpringBoot与session验证(带前后端源码)全方位全流程超详细教程
|
7月前
|
云安全 弹性计算 安全
阿里云服务器安全攻略参考:基础防护与云安全产品简介
在使用云服务器的过程中,云服务器的安全问题是很多用户非常关心的问题,阿里云服务器除了提供基础的防护之外,我们也可以选择其他的云安全类产品来确保我们云服务器的安全。本文为您介绍阿里云服务器的基础安全防护机制,以及阿里云提供的各类云安全产品,帮助用户全面了解并选择合适的防护手段,为云上业务保驾护航。
731 11
|
SQL 关系型数据库 MySQL
如何在 MySQL 或 MariaDB 中导入和导出数据库
如何在 MySQL 或 MariaDB 中导入和导出数据库
1060 0
|
SQL Java 数据库
什么是 PagingAndSortingRepository?
【8月更文挑战第21天】
258 0
|
机器学习/深度学习 算法 Python
探索Python中的基础算法:梯度提升机(GBM)
探索Python中的基础算法:梯度提升机(GBM)
642 2
|
数据可视化 数据挖掘 Python
Scipy 中级教程——信号处理
Scipy 中级教程——信号处理【1月更文挑战第8篇】
638 2
|
存储 算法 分布式数据库
分布式数据库单元复习(狗头:预习)
分布式数据库单元复习(狗头:预习)
940 0
|
存储 运维 Oracle
关于MogDB我所知的一切(一)
关于MogDB我所知的一切
1597 0
关于MogDB我所知的一切(一)