跳至正文
来两杯美式
返回

设计模式之桥接模式:抽象与实现分离,各自独立变化

By 来两杯美式
发布于

这是 2020 年 4 月整理的设计模式专题第五篇。桥接模式是结构型模式里理解门槛较高的一篇——它的核心是识别出系统中两个独立变化的维度,并用组合而不是继承把它们连起来。本文用”银行 × 账户”的例子讲透。

简单说明

桥接模式(Bridge Pattern):将抽象部分与具体实现部分分离,使它们都可以独立地变化

一句话:当系统存在两个或多个独立变化的维度时,用继承会产生类爆炸,改用组合把它们”桥接”起来。

简单示例

/**
 * 描述:账户接口,独立变化的维度之一
 */
public interface Account {
    Account openAccount();
    void printAccount();
}

/**
 * 描述:活期账号
 */
public class CurrentAccount implements Account {
    @Override
    public Account openAccount() {
        System.out.println("打开活期账号");
        return this;
    }

    @Override
    public void printAccount() {
        System.out.println("活期账号");
    }
}

/**
 * 描述:定期账号
 */
public class RegularAccount implements Account {
    @Override
    public Account openAccount() {
        System.out.println("打开定期账号");
        return this;
    }

    @Override
    public void printAccount() {
        System.out.println("定期账号");
    }
}

/**
 * 描述:银行抽象类,独立变化的维度二,里面组合一个 Account 用于独立的扩展
 */
public abstract class Bank {
    protected Account account;

    public Bank(Account account) {
        this.account = account;
    }

    protected abstract Account openAccount();
}

/**
 * 描述:农业银行
 */
public class ABCBank extends Bank {
    public ABCBank(Account account) {
        super(account);
    }

    @Override
    protected Account openAccount() {
        super.account.printAccount();
        return super.account.openAccount();
    }
}

/**
 * 描述:工商银行
 */
public class ICBCBank extends Bank {
    public ICBCBank(Account account) {
        super(account);
    }

    @Override
    protected Account openAccount() {
        super.account.printAccount();
        return super.account.openAccount();
    }
}

public class BridgeTest {
    public static void main(String[] args) {
        // 农业银行的活期账号
        Bank abcBank = new ABCBank(new CurrentAccount());
        // 工商银行的定期账号
        Bank icbcBank = new ICBCBank(new RegularAccount());
        abcBank.openAccount();
        icbcBank.openAccount();
    }
}

两个独立变化的维度

Bank 通过构造器组合一个 Account,银行与账户自由搭配:农行活期、农行定期、工行活期、工行定期,无需为每个组合建一个类。

为什么不用继承

如果不用桥接,用继承表达”银行 × 账户”:

继承方案(类爆炸):
        Bank
       /    \
   ABCBank  ICBCBank
    /   \     /   \
 活期  定期  活期  定期     ← 新增账户类型/银行都要加类

桥接方案(组合):
        Bank ──组合──> Account
       /    \            /  \
   ABCBank  ICBCBank  活期  定期

适用场景与优缺点

适用场景

优点

缺点

现实中的应用

场景两个独立变化维度
JDBC 驱动驱动类型(MySQL/Oracle) × 平台(Windows/Linux)
Java AWT 组件组件类型(Button/TextField) × 外观风格(Windows/Motif)
日志系统日志等级 × 输出目标(控制台/文件/网络)
支付系统支付渠道(支付宝/微信) × 支付方式(扫码/App)

小结


分享这篇文章:
通过邮件分享这篇文章✓ 链接已复制
查看系列全部文章
  1. 01.软件设计原则:SOLID + KISS / YAGNI / LOD 全景
  2. 02.设计模式之原型模式,及深浅拷贝
  3. 03.设计模式之工厂模式:简单工厂、工厂方法与抽象工厂
  4. 04.设计模式之建造者模式:复杂对象的组装艺术
  5. 05.设计模式之适配器模式:让不兼容的接口协同工作
  6. 06.设计模式之桥接模式:抽象与实现分离,各自独立变化
  7. 07.设计模式之装饰者模式:动态增强,比继承更有弹性
  8. 08.设计模式之代理模式:静态代理与 JDK 动态代理
  9. 09.设计模式之外观模式:统一门面,简化子系统调用
  10. 10.设计模式之享元模式:共享细粒度对象,降低内存占用
  11. 11.设计模式之策略模式:算法家族,自由切换
  12. 12.设计模式之模板方法模式:固定骨架,可变步骤
  13. 13.设计模式之观察者模式:一对多依赖,状态变更自动通知
  14. 14.设计模式之责任链模式:请求逐级传递,动态组合处理者
  15. 15.设计模式之状态模式:状态变,行为变
  16. 16.设计模式之迭代器模式:不暴露内部实现,顺序访问集合

上一篇
DDD 复杂业务系统设计(八):整洁架构 vs 六边形架构 vs DDD 分层,我选哪一种
下一篇
DDD 复杂业务系统设计(七):分层架构,你的“业务代码”应该待在哪一层