桥接模式: Bridge

简介

桥接模式是结构型模式 (Structural Patterns) 的一种.数据库

Making even a simple change to a monolithic codebase is pretty hard because you must understand the entire thing very well. Making changes to smaller, well-defined modules is much easier.设计模式

若是软件系统中某个类存在多个独立变化的维度, 经过该模式能够将这多个维度分离出来, 使他们能够独立扩展, 让系统更加符合"单一职责原则 (SRP)". 与多层继承方案不一样, 它将多个独立变化的维度设计为多个独立的继承等级结构, 而且在抽象层创建一个抽象关联, 该关联关系相似一条链接多个独立继承结构的桥, 故名桥接模式.bash

桥接模式用一种巧妙的方式处理多层继承存在的问题, 用抽象关联取代了多层继承,将类之间的静态继承关系转换为动态的对象组合关系, 使得系统更加灵活, 并易于扩展, 同时有效控制了系统中类的个数.架构

简单的例子

interface Shape {
    val shapeType: ShapeType
}

abstract class Circle : Shape {
    val shapeType = TypeCircle
    abstract val shapeColor: ShapeColor
    ...
}

abstract class Square : Shape {
    val shapeType = TypeSquare
    abstract val shapeColor: ShapeColor
    ...
}

class RedCircle : Circle() {...}
class RedSquare : Square() {...}
class BlueCircle : Circle() {...}
class BlueSquare : Square() {...}
...
复制代码

在这个例子中, 不管增长形状, 仍是增长颜色, 都会致使子类数量快速增长. 解决方案是划分红两个独立变化的维度: Type 和 Color.ui

abstract Shape(val shapeColor: ShapeColor) {
    abstract val shapeType: ShapeType
}

class Circle(val shapeColor: ShapeColor) : Shape(ShapeColor) {
    val shapeType = TypeCircle
    ...
}

class Square(val shapeColor: ShapeColor) : Shape(ShapeColor) {
    val shapeType = TypeSquare
    ...
}
复制代码

如今, 增长颜色不会再致使子类数量增长了. Shape 和 Color 直接的关系就是那座桥.spa

基本概念

在 GoF 中, 桥接模式的定义以下:.net

  1. Abstraction:拥有一个 Implementation 类型的对象引用
  2. Implementation:Implementation 和 Abstraction 接口并不必定彻底一致,实际上这两个接口能够彻底不同, Implementation 提供具体操做方法,而 Abstraction 提供更高层次的调用
  3. Concrete Implementation:实现 Implementation 接口,给出具体实现
  4. Refined Abstraction:扩展 Abstraction 中的接口定义
  5. Client: 链接 Abstraction 和 Implementation

真实的例子

伪代码见: refactoring.guru/design-patt…设计

遥控器的基类 (Remote) 中包含一个设备的引用 (device), 全部的遥控器均可以经过通用的设备接口 (Device interface) 控制设备.代理

  • 通用设备接口使得遥控器代码能够复用于遥控多种不一样的设备 (Radio / TV).
  • 经过继承遥控器基类, 能够实现只有两个按钮的简单遥控器, 或是带触摸屏的复杂遥控器.

其它真实的例子

- 驱动程序 / JDBC

应用程序使用驱动程序的方式是桥接模式的一个常见例子.版本控制

外设驱动按照制定好的接口操做外设, 使用该驱动的应用是一个 Abstraction, 它的运行结果取决于它使用的是哪个外设+驱动. 每一个驱动程序都是适配器模式 (Adapter) 的一个例子, 而使用驱动程序的应用是桥接模式的一个例子. 桥接模式将应用的开发和驱动的开发分离开来.

JDBC 是用于执行 SQL 的 Java 接口, JDBC 驱动就是实现了该接口的类. 任何一个数据库只要提供了 JDBC 驱动, Java 的数据库应用程序就能够操做它. JDBC 的这种架构将 Abstraction 和 Implementation 相分离, 使得数据库应用和数据库可以独立的发展, 是 Bridge 模式的一个极好的例子.

- VCS (Version Control System)

IDEA 的 VSC, 或者 Sourcetree 之类的软件, 均可以在一样一套 UI 下, 用一样的概念 (好比 History, Diff) 操做不一样的版本控制系统 (好比 Git, Svn).

应用场景

当一个应用/类的某个功能要支持多个变体(好比支持多个数据源)

一个应用/类越大, 弄清楚或改动的的代价就越大. 对于一个变体的改动可能会致使整个应用/类内的大量改动, 这常常会致使各类问题. Bridge 模式能够把应用/类拆分红多个独立的结构, 以后的改动就在各自的结构中, 让代码的改动影响最小化.

当一个类在多个正交的维度上可扩展时

Bridge 模式建议将每一个维度抽象成独立的继承关系, 这样以前的类能够将相关的功能和扩展代理给对应的维度去作, 而不是彻底本身作.

若是你但愿支持运行时切换实现 (Implementation)

虽然不是最重要的, 但 Bridge 模式容许你切换 Abstraction 中引用的 Implementation.

这多是 Bridge 模式容易和策略模式 (Strategy) 混淆的一个缘由. 注意: 设计模式呈现的不只是最终的代码, 还有解决问题的思路.

优缺点

优势

  • 能够用来建立跨平台的应用.
  • Client 和 Abstraction 交互, 不暴露 Implementation 的细节.
  • 开闭原则: 能够分别增长 Abstraction 和 Implementation 的子类而不相互影响.
  • 单一职责原则: Abstraction 或 Implementation 的开发人员能够 Focus 各自的代码.

缺点

  • 若是一个类的功能之间功能之间相关性较强, 使用 Bridge 模式可能会让代码变得更复杂.

和其它设计模式的关系

  • Bridge, State, Strategy (Adapter 在某种程度上也算) 有一些类似, 这些设计模式都采用了将功能代理给其它类去作的方式. 可是, 他们解决的问题并不相同. 设计模式呈现的不只是最终的代码, 还有解决问题的思路.
  • Abstract Factory 能够和 Bridge 一块儿使用, 一般用于 Abstraction 只能使用特定的 Implementation 的状况. 在这种状况下, 能够用 Abstract Factory 封装 Client 代码中创建 Abstraction 和 Implementation 链接的部分.
  • Builder 能够和 Bridge 一块儿使用, Director 做为 Abstraction, 多个 Builder 做为 Implementation.

@Uraka.Lee