桥接模式

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

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

 

posted @ 2024-01-20 17:11  wangzhilei  阅读(24)  评论(0)    收藏  举报