桥接办法

桥接办法是一种结构型规划办法, 可将一个大类或一系列紧密相关的类拆分为笼统和完结两个独立的层次结构, 然后能在开发时别离运用。

2023 跟我一起学设计模式:桥接模式

问题

笼统? 完结? 听上去挺吓人? 让咱们慢慢来, 先考虑一个简略的比方。

假设你有一个几许 形状Shape类, 从它能扩展出两个子类: 圆形Circle和 方形Square 。 你期望对这样的类层次结构进行扩展以使其包含色彩, 所以你计划创建名为 赤色Red和 蓝色Blue的形状子类。 可是, 由于你已有两个子类, 所以总共需求创建四个类才干掩盖一切组合, 例如 蓝色圆形BlueCircle和 赤色方形RedSquare 。

2023 跟我一起学设计模式:桥接模式

一切组合类的数量将以几许级数增长。

在层次结构中新增形状和色彩将导致代码杂乱程度指数增长。 例如增加三角形状, 你需求新增两个子类, 也就是每种色彩一个; 尔后新增一种新色彩需求新增三个子类, 即每种形状一个。 如此以往, 情况会越来越糟糕。

解决方案

问题的底子原因是咱们试图在两个独立的维度——形状与色彩——上扩展形状类。 这在处理类继承时是很常见的问题。

桥接办法经过将继承改为组合的办法来解决这个问题。 详细来说, 就是抽取其中一个维度并使之成为独立的类层次, 这样就能够在初始类中引证这个新层次的目标, 然后使得一个类不用具有一切的状况和行为。

2023 跟我一起学设计模式:桥接模式

将一个类层次转化为多个相关的类层次, 避免单个类层次的失控。

根据该办法, 咱们能够将色彩相关的代码抽取到具有 赤色蓝色两个子类的色彩类中, 然后在 形状类中增加一个指向某一色彩目标的引证成员变量。 现在, 形状类能够将一切与色彩相关的作业委派给连入的色彩目标。 这样的引证就成为了 形状色彩之间的桥梁。 尔后, 新增色彩将不再需求修正形状的类层次, 反之亦然。

笼统部分和完结部分

规划办法四人组的作品 在桥接界说中提出了笼统部分完结部分两个术语。 我觉得这些术语过于学术了, 反而让办法看上去比实际情况更加杂乱。 在介绍过形状和色彩的简略比方后, 咱们来看看四人组作品中让人望而生畏的词语的意义。

笼统部分 (也被称为接口) 是一些实体的高阶操控层。 该层自身不完结任何详细的作业, 它需求将作业委派给完结部分层 (也被称为渠道)。

注意, 这儿提到的内容与编程语言中的接口笼统类无关。 它们并不是一回事。

在实际的程序中, 笼统部分是图形用户界面 (GUI), 而完结部分则是底层操作系统代码 (API), GUI 层调用 API 层来对用户的各种操作做出响应。

一般来说, 你能够在两个独立方向上扩展这种运用:

  • 开发多个不同的 GUI (例如面向普通用户和管理员进行别离装备)
  • 支撑多个不同的 API (例如, 能够在 Windows、 Linux 和 macOS 上运转该程序)。

在最糟糕的情况下, 程序或许会是一团乱麻, 其中包含数百种条件句子, 连接着代码遍地不同品种的 GUI 和各种 API。

2023 跟我一起学设计模式:桥接模式

在杂乱的代码中, 即使是很小的改动都十分难以完结, 由于你有必要要在整体上对代码有充沛的了解。 而在较小且界说清晰的模块中, 进行修正则要容易得多。

你能够将特定接口-渠道的组合代码抽取到独立的类中, 以在紊乱中树立一些秩序。 可是, 你很快会发现这品种的数量很多。 类层次将以指数办法增长, 由于每次增加一个新的 GUI 或支撑一种新的 API 都需求创建更多的类。

让咱们试着用桥接办法来解决这个问题。 该办法主张将类拆分为两个类层次结构:

  • 笼统部分: 程序的 GUI 层。
  • 完结部分: 操作系统的 API。

2023 跟我一起学设计模式:桥接模式

创建跨渠道运用程序的一种办法

笼统目标操控程序的外观, 并将真实作业委派给连入的完结目标。 不同的完结只要遵从相同的接口就能够交换, 使同一 GUI 可在 Windows 和 Linux 下运转。

最终的结果是: 你无需改动与 API 相关的类就能够修正 GUI 类。 此外假如想支撑一个新的操作系统, 只需在完结部分层次中创建一个子类即可。

桥接办法结构

2023 跟我一起学设计模式:桥接模式

  1. 笼统部分 (Abstraction) 提供高层操控逻辑, 依赖于完结底层实际作业的完结目标。

  2. 完结部分 (Implementation) 为一切详细完结声明通用接口。 笼统部分仅能经过在这儿声明的办法与完结目标交互。

    笼统部分能够列出和完结部分相同的办法, 可是笼统部分通常声明一些杂乱行为, 这些行为依赖于多种由完结部分声明的原语操作。

  3. 详细完结 (Concrete Implementations) 中包含特定于渠道的代码。

  4. 准确笼统 (Refined Abstraction) 提供操控逻辑的变体。 与其父类相同, 它们经过通用完结接口与不同的完结进行交互。

  5. 通常情况下, 客户端 (Client) 仅关心怎么与笼统部分协作。 可是, 客户端需求将笼统目标与一个完结目标连接起来。

伪代码

示例演示了桥接办法怎么拆分程序中一起管理设备及其遥控器的杂乱代码。 设备Device类作为完结部分, 而 遥控器Remote类则作为笼统部分。

2023 跟我一起学设计模式:桥接模式

开始类层次结构被拆分为两个部分: 设备和遥控器。

遥控器基类声明晰一个指向设备目标的引证成员变量。 一切遥控器经过通用设备接口与设备进行交互, 使得同一个遥控器能够支撑不同类型的设备。

你能够开发独立于设备类的遥控器类, 只需新建一个遥控器子类即可。 例如, 根底遥控器或许只有两个按钮, 但你可在其根底上扩展新功用, 比方额定的一节电池或一块触摸屏。

客户端代码经过遥控器结构函数将特定品种的遥控器与设备目标连接起来。

桥接办法适合运用场景

假如你想要拆分或重组一个具有多重功用的杂乱类 (例如能与多个数据库服务器进行交互的类), 能够运用桥接办法。

类的代码行数越多, 澄清其运作办法就越困难, 对其进行修正所花费的时间就越长。 一个功用上的改变或许需求在整个类范围内进行修正, 而且常常会发生过错, 乃至还会有一些严重的副作用。

桥接办法能够将杂乱类拆分为几个类层次结构。 尔后, 你能够修正恣意一个类层次结构而不会影响到其他类层次结构。 这种办法能够简化代码的保护作业, 并将修正已有代码的风险降到最低。

假如你期望在几个独立维度上扩展一个类, 可运用该办法。

桥接主张将每个维度抽取为独立的类层次。 初始类将相关作业委派给属于对应类层次的目标, 无需自己完结一切作业。

假如你需求在运转时切换不同完结办法, 可运用桥接办法。

当然并不是说一定要完结这一点, 桥接办法可替换笼统部分中的完结目标, 详细操作就和给成员变量赋新值相同简略。

趁便提一句, 最终一点是很多人混杂桥接办法和战略办法的主要原因。 记住, 规划办法并不仅是一种对类进行组织的办法, 它还能用于交流意图和解决问题。

完结办法

  1. 清晰类中独立的维度。 独立的概念或许是: 笼统/渠道, 域/根底设施, 前端/后端或接口/完结。
  2. 了解客户端的事务需求, 并在笼统基类中界说它们。
  3. 确定在一切渠道上都可履行的事务。 并在通用完结接口中声明笼统部分所需的事务。
  4. 为你域内的一切渠道创建完结类, 但需确保它们遵从完结部分的接口。
  5. 在笼统类中增加指向完结类型的引证成员变量。 笼统部分会将大部分作业委派给该成员变量所指向的完结目标。
  6. 假如你的高层逻辑有多个变体, 则可经过扩展笼统基类为每个变体创建一个准确笼统。
  7. 客户端代码有必要将完结目标传递给笼统部分的结构函数才干使其能够彼此关联。 尔后, 客户端只需与笼统目标进行交互, 无需和完结目标打交道。

桥接办法优缺点

  • 你能够创建与渠道无关的类和程序。

  • 客户端代码仅与高层笼统部分进行互动, 不会接触到渠道的详细信息。

  • 开闭准则。 你能够新增笼统部分和完结部分, 且它们之间不会彼此影响。

  • 单一责任准则。 笼统部分专注于处理高层逻辑, 完结部分处理渠道细节。

  • 对高内聚的类运用该办法或许会让代码更加杂乱。

golang 示例及代码示例

Golang 「桥接办法」解说和代码示例 – 掘金 ()