【设计模式】桥接模式


一、桥接模式

一句话总结:抽象部分和具体实现部分分离,是它们之间可以独立的扩展,通过组合的方式建立两个类之间的联系

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

二、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类图:
    桥接模式UML
  • 说明:可以看到,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;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

发飙的蜗牛咻咻咻~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值