设计模式复习笔记 (9)结构型模式:桥接模式

来源:互联网 发布:汉高祖知乎 编辑:程序博客网 时间:2024/05/08 21:48

桥接模式(Bridge Pattern)

将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。
如果软件系统中某个类存在两个独立变化的维度,通过桥接模式可以将这两个维度分离出来,使两者可以独立扩展,让系统更加符合“单一职责原则”。


模式动机
考虑两种常见文具:毛笔和蜡笔的区别
假如我们需要大中小3种型号的画笔,能够绘制12种不同的颜色,如果使用蜡笔,需要准备3×12 = 36支,但如果使用毛笔的话,只需要提供3种型号的毛笔,外加12个颜料盒即可,涉及到的对象个数仅为 3 + 12 = 15,远小于36,却能实现与36支蜡笔同样的功能。如果增加一种新型号的画笔,并且也需要具有12种颜色,对应的蜡笔需增加12支,而毛笔只需增加一支。
为什么会这样呢?

通过分析我们可以得知:
在蜡笔中,颜色和型号两个不同的变化维度(即两个不同的变化原因)融合在一起,无论是对颜色进行扩展还是对型号进行扩展都势必会影响另一个维度;
在毛笔中,颜色和型号实现了分离,增加新的颜色或者型号对另一方都没有任何影响。
如果使用软件工程中的术语,我们可以认为在蜡笔中颜色和型号之间存在较强的耦合性,而毛笔很好地将二者解耦,使用起来非常灵活,扩展也更为方便。
在软件开发中,我们也提供了一种设计模式来处理与画笔类似的具有多变化维度的情况,即桥接模式。

假设要开发一个软件,绘制矩形、圆形、椭圆、正方形,我们至少需要4个形状类,同时如果绘制的图形还需要填充不同的颜色,如白色、灰色、黑色等,此时至少有如下两种设计方案:

  • 第一种设计方案是为每一种形状都提供一套各种颜色的版本。
  • 第二种设计方案是根据实际需要对形状和颜色进行组合。
    桥接模式
  • 方案一采用多重继承或多层继承,导致系统中类的个数急剧增加,需要提供了12个具体类,加上各级抽象层的类,系统中类的总个数要17到21个。
  • 方案一扩展麻烦,无论是增加新的图形还是新的颜色,都需要增加大量的具体类,导致系统变得非常庞大,增大运行和维护开销。究其原因,是将图形的形状和颜色两种职责集中在一个具体类中,违反了“单一职责原则”,任意一个职责发生改变都需要一个新类。
  • 方案二采用关联关系解耦,类个数更少,扩展更方便。

模式结构
桥接模式

  • Abstraction:抽象类,用于定义抽象类的接口,一般是抽象类而不是接口,其中定义了一个Implementor(实现类接口)类型的对象并可以维护该对象,它与Implementor之间具有关联关系,它既可以包含抽象业务方法,也可以包含具体业务方法。
  • RefinedAbstraction:扩充抽象类,扩充由Abstraction定义的接口,通常情况下它不再是抽象类而是具体类,它实现了在Abstraction中声明的抽象业务方法,也可以调用在Implementor中定义的业务方法。
  • Implementor:实现类接口,定义实现类的接口,这个接口不一定要与Abstraction的接口完全一致,事实上这两个接口可以完全不同,一般而言,Implementor接口仅提供基本操作,对这些基本操作进行了声明,而具体实现交给其子类。通过关联关系,Abstraction中不仅拥有自己的方法,还可以调用到Implementor中定义的方法,使用关联关系来替代继承关系。
  • ConcreteImplementor:具体实现类,具体实现Implementor接口,在不同的具体实现类中提供基本操作的不同实现,在程序运行时,具体实现类对象将替换其父类对象,提供给抽象类具体的业务操作方法。

模式优点
在很多情况下,桥接模式可以取代多重/多层继承方案,多重/多层继承方案违背了“单一职责原则”,复用性较差,且类的个数非常多,桥接模式是比继承方案更好的解决方法,它极大减少了子类的个数。
桥接模式提高了系统的可扩展性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统,符合“开闭原则”。

模式缺点
桥接模式的使用会增加系统的理解与设计难度,由于关联关系建立在抽象层,要求开发者一开始就针对抽象层进行设计与编程。
桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围具有一定的局限性,如何正确识别两个独立维度也需要一定的经验积累。

模式适用环境
在以下情况下可以使用桥接模式:

  • 如果一个系统需要在抽象化和具体化之间增加更多的灵活性,避免在两个层次之间建立静态的继承关系,通过桥接模式可以使它们在抽象层建立一个关联关系。
  • “抽象部分”和“实现部分”可以以继承的方式独立扩展而互不影响,在程序运行时可以动态将一个抽象化子类的对象和一个实现化子类的对象进行组合,即系统需要对抽象化角色和实现化角色进行动态耦合。
  • 一个类存在两个(或多个)独立变化的维度,且这两个(或多个)维度都需要独立进行扩展。
  • 对于那些不希望使用继承或因为多重/多层继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。

    模式扩展
    适配器模式与桥接模式的联用
    在软件开发中,适配器模式通常可以与桥接模式联合使用。适配器模式可以解决两个已有接口间不兼容问题,在这种情况下被适配的类往往是一个黑盒子,有时候我们不想也不能改变这个被适配的类,也不能控制其扩展。适配器模式通常用于现有系统与第三方产品功能的集成,采用增加适配器的方式将第三方类集成到系统中。桥接模式则不同,用户可以通过接口继承或类继承的方式来对系统进行扩展。
    桥接模式

0 0