设计模式 | 桥接模式

176 阅读4分钟

桥接模式,是一种结构型的设计模式,设计的关键就在于能否解耦。

Intent 意图

Decouple an abstraction from its implementation so that the two can vary independently. 将抽象和实现解耦,让它们之间可以独立变化。

一个类存在两个(或多个) 独立变化的维度,我们通过组合的方式,让这两个(或多个)维度可以独立进行扩展。双方都只依赖于抽象,而不依赖于具体实现。

Motivation 动机

将继承关系转化为组合的关系,降低了系统间的耦合,减少系统复杂和代码编写。

Applicability 适用范围

  • 拆分或者重组一个或者多重功能的复杂类,将一个复杂类拆分成几个类层次,从而实现修改任意一个类层次结构不影响其他类结构。
  • 在几个独立维度拓展一个类

Structure 结构

Decouple an abstraction from its implementation so that the two can vary independently. 将抽象和实现解耦,让它们之间可以独立变化。

注:这里的抽象并非指的是抽象类或者接口的定义,而是将一些共性的内容进行抽取、整合,从而有了一个忽略具体细节的抽象体。调用方无需具体了解某个细节,而是将这些对于细节处理不同的东西,是做同样的一个抽象体使用即可。

Participate 结构成员

结构中各个类、对象所扮演的角色

  • 抽象部分 (Abstraction) 提供高层控制逻辑,抽象化定义,并保存一个实现部分对象的引用,实际上依赖于完成底层实际工作的实现对象 (implementation)。
  • 精确抽象 (Refined Abstraction) 与其父类(抽象部分)一样, 它们通过通用实现接口与不同的实现进行交互,是修正父类的一些抽象化定义。
  • 实现对象 (Implementation) 为所有具体实现声明通用接口。 抽象部分仅能通过在这里声明的方法与实现对象交互,实现化角色应当只给出底层操作,而抽象化角色应当只给出基于底层操作的更高一层的抽象操作
  • 具体实现 (Concrete Implementations) 中包括特定于平台的代码,即,在具体平台或者环境中,实现实现对象 (Implementation) 中所定义的接口方法。
  • 通常情况下, 客户端 (Client) 仅关心如何与抽象部分合作,不关心具体实现差异或者平台差异。

Cooperation 协作

  • 实现对象不一定和抽象部分接口定义相同,抽象部分可以列出和实现部分一样的方法, 但是抽象部分通常声明一些复杂行为, 这些行为依赖于多种由实现部分声明的原语操作。 (e.g. abstraction.feature1 = implementation.method1 & method2 )。

Consequence 后果

  • Good
    • 客户端仅和高层抽象做互动,不会接触到底层信息
    • 符合单一职责和开闭
    • 抽象和实现都可以进行独立拓展
  • Bad
    • 系统复杂度增加

Implementation 示例

如果使用 类 来进行拓展,当出现多个维度的时候,如下例,一个几何体拥有 shape & color 两个维度,如果想要表达红色的正方体,那就需要新建一个类,保存 shape & color,而如果再加上质量、粗糙 or 光滑 等等不同维度属性,则系统内的类的数量就会大爆炸。

而,如果我们将属性,通过组合的形式,组合起来,shape 里面包含一个 color 属性,而具体 color 以组合的方式传入。

Known uses 已知应用

JDBC 数据库驱动等等

Related Pattern 和其他模式直接的关系

桥接、适配器、策略、状态

  • 都是基于组合的方式,将工作委派给其他对象,但是各自的意图不同。
  • 桥接:解耦实现,实现相互依赖的类可以独立变化
  • 适配器:改变一个类的接口,实现兼容
  • 策略:提供多个可以相互替代的方法
  • 状态:封装基于状态的行为,使用委托进行行为的切换
// 实现部分的抽象接口定义
interface MsgRender {
    send(msg: string): void
}

// 具体实现对象
class PhoneMsgRender implements MsgRender {
    private phoneNumber = []

    constructor(phones?: string[]) {
        this.phoneNumber = phones ?? []
    }

    send(msg: string): void {
        console.log('phoning')
        console.log(`${msg}`)
    }
}

class EmailMsgRender implements MsgRender {
    private emailAddress = []

    constructor(emailAddress?: string[]) {
        this.emailAddress = emailAddress ?? []
    }

    send(msg: string): void {
        console.log('emailing')
        console.log(`${msg}`)
    }
}

// 抽象部分
abstract class Notification {
    // key method 持有实现对象的引用
    protected msgRender: MsgRender

    constructor(msgRender: MsgRender) {
        this.msgRender = msgRender
    }

    abstract notify(msg: string): void
}

// 可以理解为 refine abstration 抽象部分的修正
class DangerNotificaton extends Notification {
    message: string = '[Warning]'
    constructor(msgRender: MsgRender) {
        super(msgRender)
    }

    notify(msg: string): void {
        this.msgRender.send(`${this.message}: ${msg}`)
    }
}
// 可以理解为 refine abstration 抽象部分的修正
class InfoNotificaton extends Notification {
    message: string = '[Info]'
    constructor(msgRender: MsgRender) {
        super(msgRender)
    }

    notify(msg: string): void {
        this.msgRender.send(`${this.message}: ${msg}`)
    }
}

// context
const dangerNotificaton = new DangerNotificaton(new PhoneMsgRender())
dangerNotificaton.notify('The error count reach limited number')
const infoNotificaton = new InfoNotificaton(new EmailMsgRender())
infoNotificaton.notify('The error count reach limited number')

往期文章 index 【持续更新中】

设计模式专栏 Index

Reference:(文章参考 or 图片来源)

  1. www.cnblogs.com/forlina/arc…
  2. www.cnblogs.com/zhenyulu/ar…
  3. refactoringguru.cn/design-patt…