一、桥梁(Bridge)模式
桥梁模式是一个非常有用的模式,也是比较复杂的一个模式。熟悉这个模式对于理解面向对象的设计原则,包括"开-闭"原则(OCP)以及组合/聚合复用原则(CARP)都很有帮助。理解好这两个原则,有助于形成正确的设计思想和培养良好的设计风格。
注:《Java与模式》一书认为Bridge模式不是一个使用频率很高的模式,我不太赞同,我认为Bridge模式中蕴涵了很多设计模式的关键思想在里面,所以我这里采纳了《Design Patterns Explained》一书的作者Alan Shalloway与James R. Trott的观点:The Bridge pattern is quite a bit more complex than the other patterns you just learned;
it is also much more useful.
桥梁模式的用意
【GOF95】在提出桥梁模式的时候指出,桥梁模式的用意是"将抽象化(Abstraction)与实现化(Implementation)脱耦,使得二者可以独立地变化"。这句话有三个关键词,也就是抽象化、实现化和脱耦。
抽象化
存在于多个实体中的共同的概念性联系,就是抽象化。作为一个过程,抽象化就是忽略一些信息,从而把不同的实体当做同样的实体对待【LISKOV94】。
实现化
抽象化给出的具体实现,就是实现化。
脱耦
所谓耦合,就是两个实体的行为的某种强关联。而将它们的强关联去掉,就是耦合的解脱,或称脱耦。在这里,脱耦是指将抽象化和实现化之间的耦合解脱开,或者说是将它们之间的强关联改换成弱关联。
将两个角色之间的继承关系改为聚合关系,就是将它们之间的强关联改换成为弱关联。因此,桥梁模式中的所谓脱耦,就是指在一个软件系统的抽象化和实现化之间使用组合/聚合关系而不是继承关系,从而使两者可以相对独立地变化。这就是桥梁模式的用意。
二、桥梁模式的结构
桥梁模式【GOF95】是对象的结构模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。
下图所示就是一个实现了桥梁模式的示意性系统的结构图。
可以看出,这个系统含有两个等级结构,也就是:
- 由抽象化角色和修正抽象化角色组成的抽象化等级结构。
- 由实现化角色和两个具体实现化角色所组成的实现化等级结构。
桥梁模式所涉及的角色有:
-
抽象化(Abstraction)角色:抽象化给出的定义,并保存一个对实现化对象的引用。
-
修正抽象化(Refined Abstraction)角色:扩展抽象化角色,改变和修正父类对抽象化的定义。
-
实现化(Implementor)角色:这个角色给出实现化角色的接口,但不给出具体的实现。必须指出的是,这个接口不一定和抽象化角色的接口定义相同,实际上,这两个接口可以非常不一样。实现化角色应当只给出底层操作,而抽象化角色应当只给出基于底层操作的更高一层的操作。
-
具体实现化(Concrete Implementor)角色:这个角色给出实现化角色接口的具体实现。
三、桥梁模式的示意性源代码
四、调制解调器问题
感觉《敏捷软件开发-原则、模式与实践》中关于Bridge模式的例子很好。(《Java与模式》一书33章的对变化的封装一节也写得很不错,推荐大家读一读。它深入的阐述了《Design Patterns Explained》一书中"1)Design to interfaces. 2)Favor composition over inheritance. 3)Find what varies and encapsulate it"的三个观点。)。
如图所示,有大量的调制解调器客户程序在使用Modem接口。Modem接口被几个派生类HayesModem、USRoboticsModem和EarniesModem实现。它很好地遵循了OCP、LSP和DIP。当增加新种类的调制解调器时,调制解调器的客户程序不会受影响。
假定这种情形持续了几年,并有许多调制解调器的客户程序都在使用着Modem接口。现出现了一种不拨号的调制解调器,被称为专用调制解调器。它们位于一条专用连接的两端。有几个新应用程序使用这些专用调制解调器,它们无需拨号。我们称这些使用者为DedUser。但是,客户希望当前所有的调制解调器客户程序都可以使用这些专用调制解调器。他们不希望去更改许许多多的调制解调器客户应用程序,所以完全可以让这些调制解调器客户程序去拨一些假(dummy)电话号码。
如果能选择的话,我们会把系统的设计更改为下图所示的那样。
我们把拨号和通信功能分离为两个不同的接口。原来的调制解调器实现这两个接口,而调制解调器客户程序使用这两个接口。DedUser只使用Modem接口,而DedicateModem只实现Modem接口。但这样做会要求我们更改所有的调制解调器客户程序--这是客户不允许的。
一个可能的解决方案是让DedicatedModem从Modem派生并且把dial方法和hangup方法实现为空,就像下面这样:
几个月后,已经有了大量的DedUser,此时客户提出了一个新的更改。为了能拨国际电话号码、信用卡电话、PIN标识电话等等,必修对现有dial中使用char[10]存储号码改为能够拨打任意长度的电话号码。
显然,所有的调制解调器客户程序都必须更改。客户同意了对调制解调器客户程序的更改,因为他们别无选择。糟糕的是,现在必须要去告诉DedUser的编写者,他们必须要更改他们的代码!你可以想象他们听到这个会有多高兴。本来他们是不用调用dial的。
这就是许多项目都会具有的那种有害的混乱依赖关系。系统某一部分中的一个杂凑体(kludge)创建了一个有害的依赖关系,最终导致系统中完全无关的部分出现问题。
如果使用ADAPTER模式解决最初的问题的话,就可以避免这个严重问题。如图:
请注意,杂凑体仍然存在。适配器仍然要模拟连接状态。然而,所有的依赖关系都是从适配器发起的。杂凑体和系统隔离,藏身于几乎无人知晓的适配器中。
BRIDGE模式
看待这个问题,还有另外一个方式。现在,出现了另外一种切分Modem层次结构的方式。如下图:
这不是一个理想的结构。每当增加一款新硬件时,就必须创建两个新类--一个针对专用的情况,一个针对拨号的情况。每当增加一种新连接类型时,就必须创建3个新类,分别对应3款不同的硬件。如果这两个自由度根本就是不稳定的,那么不用多久,就会出现大量的派生类。
在类型层次结构具有多个自由度的情况中,BRIDGE模式通常是有用的。我们可以把这些层次结构分开并通过桥把它们结合到一起,而不是把它们合并起来。如图:
我们把调制解调器类层次结构分成两个层次结构。一个表示连接方法,另一个表示硬件。
这个结构虽然复杂,但是很有趣。它的创建不会影响到调制解调器的使用者,并且还完全分离了连接策略和硬件实现。ModemConnectController的每个派生类代表了一个新的连接策略。在这个策略的实现中可以使用sendlmp、receivelmp、diallmp和hanglmp。新imp方法的增加不会影响到使用者。可以使用ISP来给连接控制类增加新的接口。这种做法可以创建出一条迁移路径,调制解调器的客户程序可以沿着这条路径慢慢地得到一个比dial和hangup层次更高的API。
五、另外一个实际应用Bridge模式的例子
该例子演示了业务对象(BusinessObject)通过Bridge模式与数据对象(DataObject)解耦。数据对象的实现可以在不改变客户端代码的情况下动态进行更换。
六、在什么情况下应当使用桥梁模式
根据上面的分析,在以下的情况下应当使用桥梁模式:
- 如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的联系。
- 设计要求实现化角色的任何改变不应当影响客户端,或者说实现化角色的改变对客户端是完全透明的。
- 一个构件有多于一个的抽象化角色和实现化角色,系统需要它们之间进行动态耦合。
- 虽然在系统中使用继承是没有问题的,但是由于抽象化角色和具体化角色需要独立变化,设计要求需要独立管理这两者。
分享到:
相关推荐
Bridge模式是一种设计模式,属于结构型模式之一,其主要目的是将抽象部分与实现部分分离,使得两者可以独立地进行变化。这种模式的核心思想是“抽象不应该依赖于具体,而应该依赖于抽象”。Bridge模式通过引入一个...
本文将介绍 Bridge 模式,它是一种结构型设计模式,用于解耦抽象与实现,增强软件系统的灵活性和可扩展性。 二、Bridge 设计模式的别名 Handle/Body 三、Bridge 设计模式的意图 Bridge 设计模式是 Java 中的一种结构...
本资料主要探讨了Docker的网络桥接模式(Bridge模式)以及其默认网络设备docker0,这对于理解和运用Docker服务至关重要。 首先,Docker的Bridge模式是Docker容器默认的网络模式。在这个模式下,每个容器都会被分配...
Bridge模式是一种设计模式,主要目的是将抽象部分与实现部分解耦,使得它们可以独立地进行变化。在Java编程中,这种模式的应用可以帮助我们构建更灵活、可扩展的系统。Bridge模式通常由四个主要角色组成:抽象...
Bridge模式是对抽象和具体的进一步抽象。假设你有一个抽象类,一个具体类,现在需要将两者的变化都考虑进去,这就需要bridge。这是经典设计模式中唯一的可以同时处理抽象和具体同时变化的设计模式
Docker在创建容器时有四种网络模式,bridge为默认不需要用--net去指定,其他...那Docker为网络bridge模式指定容器ip该如何实现呢?下面通过通过这篇文章一起看看吧,文中给出了详细的示例代码,有需要的可以参考借鉴。
桥模式(Bridge模式)是一种设计模式,主要用于将抽象部分与实现部分解耦,使得它们能够独立地变化。在Java中,这种模式可以帮助我们构建更加灵活和可扩展的系统。以下是关于桥模式的详细解释: 首先,理解桥模式的...
软件设计模式,共包含二十多种模式,做IT的必备知识呀!
在给定的文件列表中,我们可以看到涉及到Bridge模式的一些关键组件: 1. **Abstraction**(抽象类):这是桥接模式的核心抽象部分,定义了客户需要的接口,并持有一个指向实现部分的指针。在`abstraction.cpp`和`...
这就要使用Bridge模式。 意图 将抽象部分与实现部分分离,使它们都可以独立的变化。[GOF《设计模式》] 结构图图1Bridge模式结构图 生活中的例子 桥接模式将抽象部分与它的实现分离,使它们能够独立地变化。一个...
《Java实现的23种设计模式——Bridge模式详解》 设计模式是软件工程中的宝贵经验总结,它们为解决常见问题提供了可复用的解决方案。在众多设计模式中,Bridge模式是一种结构型模式,旨在将抽象部分与其实现部分分离...
Java设计模式中的Bridge模式是一种结构型设计模式,其主要目的是将抽象部分与其实现部分分离,使得两者可以独立地进行变化。在Bridge模式中,抽象类(或接口)不直接包含实现,而是通过一个引用(或接口)指向实现类...
在上述例子中,Bridge模式被用来解决咖啡种类的问题。咖啡可以按照杯型(中杯、大杯)和是否加奶(加奶、不加奶)来分类。如果简单地使用继承,会形成一个四层的类结构,这将导致类的复杂性和扩展困难。Bridge模式...
我们需要选择Bridge模式,并启用DHCP使能。这将允许电脑连接光猫时可以自动获得IP地址。然后,我们需要访问光猫的配置页面,并勾选业务模式为INTERNET,vlan模式改为TAG,vlanid为200,802.1p优先级为6。 步骤3:...
Bridge 模式是一种结构型模式,用于提供一种分离对象的接口和实现的接口。Bridge 模式的优点是可以提供一种统一的分离对象的接口和实现的接口,减少了代码的耦合度。Bridge 模式的缺点是它可能会增加代码的复杂度。 ...
Bridge 模式是一种结构型设计模式,主要用于将抽象部分与实现部分分离,使得它们可以独立地变化。它可以使得抽象部分和实现部分之间的绑定变得松散,从而提高了系统的灵活性和可维护性。 2. ACE 框架中的 Bridge ...