CH07-结构型-桥接

模式动机

设想如果要绘制矩形、圆形、椭圆、正方形,至少需要四种形状类,但是如果绘制的图形具有不同的颜色,此时至少有以下两种设计方案:

  1. 为每一种形状都提供一套各种颜色的版本
  2. 根据实际需要对形状和颜色进行组合

对于有两个变化维度的系统,采用第二种方案进行设计则类的个数更少,系统扩展也更方便。方案二即为桥接模式,该模式将继承关系转换为关联关系,减少耦合和编码量。

模式定义

桥接模式(Bridge Pattern),将抽象部分与它的实现部分分离,使他们都可以独立变化。又称为柄体模式(Handle and Body)接口模式(Interface)

模式结构

包含四种角色:

  • Abstraction:抽象类
  • RefinedAbstraction:扩充抽象类
  • Implementor:实现类接口
  • ConcreteImplementor:具体实现类

类图

NAME

时序图

NAME

代码分析

int main(int argc, char argv[]){
  Implementor * pImp = new ConcreteImplementorA();
  Abstraction * pa = new RefinedAbstraction();
  pa->operation();
  
  Abstraction * pb = new RefinedAbstraction(new ConcreteImplementorB());
  pb->operation();
  ...
}

模式分析

理解桥接模式,重点需要理解如何将抽象化(Abstraction)和实现化(Implementation)解耦,使得二者可以独立的变化。

  1. 抽象化:抽象化就是忽略一些信息,把不同的实体当做同样的实体对待,将对象的共同性质抽取出来形成类的过程即为抽象化;
  2. 解耦:解耦就是将抽象化和实现化之间的耦合解脱开,或者将他们之间的强关联转换成弱关联,将两个角色之间的继承关系改为关联关系。桥接模式中的解耦,是指在一个软件系统的抽象化和实现化之间使用关联关系(组合、聚合),而不是继承关系,从而使两者可以相互独立的变化,也就是桥接模式的动机。

实例

如果需要开发一个跨平台的视频播放器,可以在不同操作系统平台上播放多种格式的视频文件,常见的视频格式包括 MPEG、RMVB、AVI、WMV 等。

优点

  • 分离抽象接口及其实现部分。
  • 桥接模式有时类似于多继承方案,但是多继承方案违背了类的单一职责原则(一个类只有一个变化的原因),复用性较差,而且多继承中类的个数非常庞大,桥接则是更好的方法。
  • 提高了系统的可扩充性,在两个变化维度任意扩展一个维度,都不需要修改原有的系统。
  • 实现细节对客户透明,可以对用户隐藏实现细节。

缺点

  • 桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。
  • 要求正确识别出系统中两个独立变化的维度,使用范围有一定局限性。

适用场景

  • 如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多灵活性,避免在两个层次之间建立静态继承关系,通过桥接模式可以使他们在抽象层建立一个关联关系。
  • 抽象化角色和实现化角色可以以继承的方式独立扩展而互不影响,在程序运行时可以动态将一个抽象化子类的对象和一个实现化子类的对象进行组合,即系统需要对抽象化角色和实现化角色进行动态耦合。
  • 一个类存在两个独立变化的维度,且这两个维度都需要独立扩展。
  • 虽然在系统中使用继承是没有问题的,但是由于抽象化角色和实现化角色需要独立变化,设计要求独立管理这两者。
  • 对于那些不希望使用继承或因为多层继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。

模式扩展

适配器与桥接模式联用:

​ 桥接模式和适配器模式用于设计的不同阶段。桥接模式用于系统的初步设计,对于存在两个独立变化维度的类可以将其分为抽象化和实现化两个角色,使他们可以进行分别变化;在初步设计完成后,当发现系统与已有类无法协同工作时,可以使用适配器模式。有时也需要在设计初期使用适配器模式,尤其是在那些涉及大量第三方应用接口的时候。