首页 > 其他分享 >桥接模式

桥接模式

时间:2024-01-20 17:22:46浏览次数:33  
标签:Account String 桥接 void 模式 class new public

  • 定义:将抽象部分与它的具体实现部分分离,使它们都可以独立的变化,通过组合的方式建立两个类之间的联系,而不是继承
  • 类型:结构型
  • 适用场景:
    •   抽象和具体实现之间增加更多的灵活性
    •   一个类存在两个(或多个)独立变化的维度,且这两个(或多个)维度都需要独立进行扩展
    •   不希望使用继承,或因为多层继承导致系统类的个数剧增
  • 优点:
    •   分离抽象部分及其具体实现部分
    •   提高了系统的可扩展性
    •   符合开闭原则
    •   符合合成复用原则
  • 缺点:
    •   增加了系统的理解与设计难度
    •   需要正确的识别出系统中两个独立变化的维度
  • 相关设计模式:
    •   桥接模式和组合模式:组合模式强调的是部分和整体间的组合,而桥接模式强调的是平行级别上不同类的组合
    •   桥接模式和适配器模式:都是让两个东西配合工作,两个模式的目的又不一样,适配器是改变已有的接口,让它们之间可以相互配合,而桥接模式是分离抽象和具体的实现,目的是分离

coding(各驱动之间设计)

实现层
/**
 * <p>数据库驱动接口</p>
 */
public interface IDriver {
    /**
     * 连接
     */
    void connect();
}
/**
 * <p>MySql数据库驱动类</p>
 */
public class MySqlDriver implements IDriver {

    private String url;
    private String user;
    private String pwd;

    public MySqlDriver(String url, String user, String pwd) {
        this.url = url;
        this.user = user;
        this.pwd = pwd;
    }

    @Override
    public void connect() {
        System.out.println("url:" + this.url);
        System.out.println("user:" + this.user);
        System.out.println("pwd:" + this.pwd);
        System.out.println("mysql驱动连接数据库");
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getUser() {
        return user;
    }

    public void setUser(String user) {
        this.user = user;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
}
/**
 * <p>Oracle数据库驱动类</p>
 */
public class OracleDriver implements IDriver {
    @Override
    public void connect() {
        System.out.println("oracle驱动连接数据库");
    }
}
/**
 * <p>PostGreSql数据库驱动类</p>
 */
public class PostgreSqlDriver implements IDriver {
    @Override
    public void connect() {
        System.out.println("postgresql驱动连接数据库");
    }
}

抽象层

/**
 * <p>各驱动之间的桥梁</p>
 *
 */
public abstract class AbstractBridge {

    // 聚合和关联驱动接口实例
    private IDriver driver;

    public IDriver getDriver() {
        return driver;
    }

    public void setDriver(IDriver driver) {
        this.driver = driver;
    }

    public abstract void connect();
}
/**
 * <p>驱动管理器 == 实现不同驱动设备之间的数据库连接</p>
 *
 */
public class DriverManager extends AbstractBridge {
    @Override
    public void connect() {
        getDriver().connect();
    }
}

UML

coding(绘制图案)

实现层
/**
 * <p>颜色接口</p>
 *
 */
public interface Color {
    void painting(String shape);
}
/**
 * <p>绿色</p>
 *
 */
public class Green implements Color {
    @Override
    public void painting(String shape) {
        System.out.println("绘制绿色的" + shape);
    }
}
/**
 * <p>红色</p>
 *
 */
public class Red implements Color {
    @Override
    public void painting(String shape) {
        System.out.println("绘制红色的" + shape);
    }
}
/**
 * <p>白色</p>
 *
 */
public class White implements Color {
    @Override
    public void painting(String shape) {
        System.out.println("绘制白色的" + shape);
    }
}

抽象层

/**
 * <p>抽象形状类 -- 聚合与关联Color实现类</p>
 *
 */
public abstract class AbstractShape {

    private Color color;

    public Color getColor() {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;
    }

    /**
     * 抽象方法 == 绘制图案
     */
    abstract void draw();
}
/**
 * <p>圆形</p>
 *
 */
public class Circle extends AbstractShape {
    @Override
    public void draw() {
        getColor().painting("圆形");
    }
}
/**
 * <p>矩形、长方形</p>
 *
 */
public class Rectangle extends AbstractShape {
    @Override
    public void draw() {
        getColor().painting("矩形");
    }
}
/**
 * <p>正方形</p>
 *
 */
public class Square extends AbstractShape {
    @Override
    public void draw() {
        getColor().painting("正方形");
    }
}

UML

测试

/**
 * <p>桥接模式测试</p>
 *
 */
public class BridgeTest {

    public static void main(String[] args) {
        driverConnect();
        drawShape();

        /**
         * 1、分离抽象接口及其实现部分。提高了比继承更好的解决方案
         * 2、桥接模式提高了系统的可扩充性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统
         * 3、对客户隐藏实现细节
         */
    }

    /**
     * 不同驱动连接数据库
     */
    private static void driverConnect() {

        DriverManager driverManager = new DriverManager();
        String url = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&autoReconnect=true&rewriteBatchedStatements=true";
        String user = "root";
        String pwd = "root";
        // mysql驱动连接数据库
        IDriver mySqlDriver = new MySqlDriver(url, user, pwd);
        driverManager.setDriver(mySqlDriver);
        driverManager.connect();
        System.out.println("========= 分割线 =========");
        // oracle驱动连接数据库
        IDriver oracleDriver = new OracleDriver();
        driverManager.setDriver(oracleDriver);
        driverManager.connect();
        System.out.println("\n========= 分割线 =========\n");
    }

    /**
     * 绘制不同颜色的形状
     */
    private static void drawShape() {

        //绘制红色的矩形
        Color red = new Red();
        Rectangle rectangle = new Rectangle();
        rectangle.setColor(red);
        rectangle.draw();

        //绘制绿色的正方形
        Color green = new Green();
        Square square = new Square();
        square.setColor(green);
        square.draw();

        //绘制白色的圆形
        Color white = new White();
        Circle circle = new Circle();
        circle.setColor(white);
        circle.draw();
    }
}
========结果=========
url:jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&autoReconnect=true&rewriteBatchedStatements=true
user:root
pwd:root
mysql驱动连接数据库
========= 分割线 =========
oracle驱动连接数据库

========= 分割线 =========

绘制红色的矩形
绘制绿色的正方形
绘制白色的圆形

coding((各个)银行和(活期、定期)账户的设计)

实现层

账户接口和活期定期账户

public interface Account {
    Account openAccount();
    void showAccountType();
}
public class DepositAccount implements Account {
    @Override
    public Account openAccount() {
        System.out.println("打开定期账号");
        return new DepositAccount();
    }

    @Override
    public void showAccountType() {
        System.out.println("这是一个定期账号(委托给实现处理)");
    }
}
public class SavingAccount implements Account {
    @Override
    public Account openAccount() {
        System.out.println("打开活期账号");
        // ...
        return new SavingAccount();
    }

    @Override
    public void showAccountType() {
        System.out.println("这是一个活期账号(委托给实现处理)");
    }
}

抽象层

银行抽象类和ABC、ICBC银行

public abstract class Bank {
    protected Account account;
    public Bank(Account account){
        this.account = account;
    }
    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;
    }
}

UML

IMG_256

可以看到,UML类图左侧是实现层,右侧是抽象层,所以桥接模式最重要的是把桥的两侧划分清楚,Account可以理解为桥的实现接口,下面两个是其具体实现类,然后右边是Bank抽象类,注意它通过组合的方式使用了左侧Account接口,这就是桥接模式的核心。通过桥接模式,把实现部分(左侧)和抽象部分(右侧)进行一个桥接,通过组合方式结合合成复用原则来达到抽象层和实现层分离,并且各自可以独立发展,如果要加一个银行,在右侧抽象层继承抽象类即可,要加一个账号,在左侧实现接口即可。

测试

public class Test {
    public static void main(String[] args) {
        Bank icbcBank = new ICBCBank(new DepositAccount());
        Account icbcAccount = icbcBank.openAccount();
        icbcAccount.showAccountType();

        Bank icbcBank2 = new ICBCBank(new SavingAccount());
        Account icbcAccount2 = icbcBank2.openAccount();
        icbcAccount2.showAccountType();

        Bank abcBank = new ABCBank(new SavingAccount());
        Account abcAccount = abcBank.openAccount();
        abcAccount.showAccountType();
    }
}
======结果=====
打开中国工商银行账号
打开定期账号(委托给实现处理)
这是一个定期账号
打开中国工商银行账号
打开活期账号(委托给实现处理)
这是一个活期账号
打开中国农业银行账号
打开活期账号(委托给实现处理)
这是一个活期账号

 

注意:

还有个要注意的点在于,银行具体的实现类方法 openAccount() 里面,不要所有的实现都自己完成,而是要委托给account去实现,因为只有通过具体的委托,以后account里边的 openAccount() 无论如何扩展的话,Bank里面的 openAccount() 是不用动的,不要把实现挪到抽象的里面,要把具体的行为委托出去。

源码中的应用

  • java.sql.Driver:Java数据库驱动,mysql的jdbc实现了Driver,如果添加了oracle,那么oracle的jdbc也会实现Driver,那它们是如何获取连接的呢,可以打开以下这个类
  • java.sql.DriverManager:DriverManager 类有个DriverInfo 列表,其实它就是对Driver的具体封装,DriverManager类有个registerDriver方法,把Driver注册进来,驱动注册完之后,可以看看它里面getConnection方法,通过这个静态方法获取具体的连接,于是jdbc通过DriverManager,对外提供了操作数据库的统一接口,通过这个方法可以获取不同的数据库连接,并且通过返回值Connection里边提供了具体方法来对数据库进行操作,那jdbc为不同的数据库提供了相同的操作方法,无论是操作mysql还是操作oracle里面的方法是一样的。
public class DriverManager {
    ...
    // List of registered JDBC drivers
    private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();
    ...

    public static synchronized 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);

    }
    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()));
    }
}

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

 

标签:Account,String,桥接,void,模式,class,new,public
From: https://www.cnblogs.com/wangzhilei-src/p/17976756

相关文章

  • 学习笔记——KMP模式匹配
    KMP模式匹配KMP算法能够在线性时间内判定字符串\(A\left[1\simN\right]\)是否是字符串\(B\left[1\simM\right]\)的字串,并求出字符串\(A\)在字符串\(B\)中各次出现的位置。详细来讲,KMP算法分为两步。对字符串\(A\)进行自我匹配求出一个数组\(next\),\(next\lef......
  • 将小部分源码设计精髓带入到开发中来(工厂模式、适配器模式、抽象类、监听器)
    前言咋说呢,大学期间阅读过很多源码(Aop、Mybatis、Ioc、SpringMvc…),刚开始看这些源码的时候觉得云里雾里,一个没什么代码量的人突然去接触这种商业帝国级别的成品源码的时候,根本无从下手,这种感觉很难受,但是也庆幸自己熬过了那段难忘且充实的日子,随着自己代码量的慢慢增多,也开始慢慢......
  • spring--是如何解决单例模式下循环依赖问题的
    Spring解决单例bean的循环依赖主要依赖于容器的三级缓存机制,以及bean的提前暴露。这里是它如何工作的:三级缓存:一级缓存(singletonObjects):存储已经经过完整生命周期处理的单例bean,包括初始化和依赖注入等。二级缓存(earlySingletonObjects):存储早期的单例对象的引用,这些......
  • 设计模式:结构型模式(套路:包一层)
    文章目录结构型模式(StructuralPattern)1.适配器模式(Adapter)1.1.定义1.2.结构1.3.时序图1.4.代码实现1.4.1.对象适配器模式实现1.4.2.类适配器模式实现1.5.优缺点1.5.1.对象适配器模式1.5.2.类适配器模式1.6.使用场景1.7.总结2.桥接模式(Bridge)2.1.定义2.2......
  • BZOJ1717 Milk Patterns 产奶的模式 (二分+后缀数组+height数组)
    发现这样起标题更能引流(ylg实锤了)题意给定一个长度为\(n\)的数组\(a\),求在\(a\)中出现了至少\(k\)次的最长子串的长度。解法考虑将一个子串拆成两个后缀,即\([l,r]=[l,n]-[r,n]\),发现一个长度为\(x\)的子串\(t\)在\(i,j\)两个位置出现过当且仅当后缀\(i,j\)有......
  • 链路聚合(手工负载分担模式)
    作者:兔砸网工-反骨的胖1.以太网链路聚合简介        以太网链路聚合Eth-Trunk简称链路聚合,通过将多个物理接口捆绑为一个逻辑接口,以达到增加链路带宽、提高链路聚合接口可靠性、实现链路负载分担的目的。根据是否启用链路聚合控制协议LACP,链路聚合分为手工负载分担模式和LA......
  • freeswitch on centos dockerfile模式
     概述freeswitch是一款简单好用的VOIP开源软交换平台。centos7docker上编译安装fs的流程记录,本文使用dockerfile模式。环境dockerengine:Version24.0.6centosdocker:7freeswitch:v1.6.20dockerfile创建空目录,创建dockerfile文件。github访问经常失败,先下载好源码包,并......
  • 新能源汽车智慧充电桩方案:智能高效的充电桩管理模式及应用场景
    一、行业背景随着全球对环境保护的日益重视,新能源汽车成为了未来的发展趋势。而充电桩作为新能源汽车的核心基础设施,其智慧化的解决方案对于推动新能源汽车的普及和发展至关重要。通过智能化、高效化的充电服务,提高用户体验,满足快速增长的电动汽车充电需求已经成为当前行业发......
  • 手写 Mybatis-plus 基础架构(工厂模式+ Jdk 动态代理统一生成代理 Mapper)
    这里写目录标题前言温馨提示手把手带你解析@MapperScan源码手把手带你解析@MapperScan源码细节剖析工厂模式+Jdk代理手撕脚手架,复刻BeanDefinitionRegistryPostProcessor手撕FactoryBean代理Mapper在Spring源码中的生成流程手撕MapperProxyFactory手撕增强逻辑Invoca......
  • Windows 10调用 Microsoft Edge 展台模式功能
    使用展台模式功能可以使用以下数字/交互式标牌和公共浏览的命令行选项Windows10调用MicrosoftEdge展台模式功能。展台模式数字/交互式标牌复制 msedge.exe--kioskwww.contoso.com--edge-kiosk-type=fullscreen展台模式公共浏览复制 msedge.exe--kiosk......