深入浅出设计模式(7)——Bridge模式

深入浅出设计模式(7)——Bridge模式概述 Bridage 模式就是把抽象部分和它的实现部分分离开来 让两者可独立变化

大家好,欢迎来到IT知识分享网。

概述

桥梁模式是一个非常有用的模式,也是比较复杂的一个模式。熟悉这个模式对于理解面向对象的设计原则,包括”开-闭”原则(OCP)以及组合/聚合复用原则(CARP)都很有帮助。理解好这两个原则,有助于形成正确的设计思想和培养良好的设计风格。

桥梁模式的用意

二、 桥梁模式的结构

桥梁模式【GOF95】是对象的结构模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。

下图所示就是一个实现了桥梁模式的示意性系统的结构图。

深入浅出设计模式(7)——Bridge模式

可以看出,这个系统含有两个等级结构,也就是:

  • 由抽象化角色和修正抽象化角色组成的抽象化等级结构。
  • 由实现化角色和两个具体实现化角色所组成的实现化等级结构。

桥梁模式所涉及的角色有:

  • 抽象化(Abstraction)角色: 抽象化给出的定义,并保存一个对实现化对象的引用。
  • 修正抽象化(Refined Abstraction)角色: 扩展抽象化角色,改变和修正父类对抽象化的定义。
  • 实现化(Implementor)角色: 这个角色给出实现化角色的接口,但不给出具体的实现。必须指出的是,这个接口不一定和抽象化角色的接口定义相同,实际上,这两个接口可以非常不一样。实现化角色应当只给出底层操作,而抽象化角色应当只给出基于底层操作的更高一层的操作。
  • 具体实现化(Concrete Implementor)角色: 这个角色给出实现化角色接口的具体实现。


三、 桥梁模式的示意性源代码

 

深入浅出设计模式(7)——Bridge模式 // Bridge pattern — Structural example  
深入浅出设计模式(7)——Bridge模式
using System;
深入浅出设计模式(7)——Bridge模式
深入浅出设计模式(7)——Bridge模式

// “Abstraction”
深入浅出设计模式(7)——Bridge模式
class Abstraction
深入浅出设计模式(7)——Bridge模式深入浅出设计模式(7)——Bridge模式
深入浅出设计模式(7)——Bridge模式 {

深入浅出设计模式(7)——Bridge模式   
// Fields
深入浅出设计模式(7)——Bridge模式
   protected Implementor implementor;
深入浅出设计模式(7)——Bridge模式
深入浅出设计模式(7)——Bridge模式   

// Properties
深入浅出设计模式(7)——Bridge模式
   public Implementor Implementor
深入浅出设计模式(7)——Bridge模式深入浅出设计模式(7)——Bridge模式   
深入浅出设计模式(7)——Bridge模式 {

深入浅出设计模式(7)——Bridge模式深入浅出设计模式(7)——Bridge模式     
set 深入浅出设计模式(7)——Bridge模式 { implementor = value; }
深入浅出设计模式(7)——Bridge模式    }

深入浅出设计模式(7)——Bridge模式
深入浅出设计模式(7)——Bridge模式   

// Methods
深入浅出设计模式(7)——Bridge模式
   virtual public void Operation()
深入浅出设计模式(7)——Bridge模式深入浅出设计模式(7)——Bridge模式   
深入浅出设计模式(7)——Bridge模式 {

深入浅出设计模式(7)——Bridge模式      implementor.Operation();
深入浅出设计模式(7)——Bridge模式    }


深入浅出设计模式(7)——Bridge模式 }

深入浅出设计模式(7)——Bridge模式
深入浅出设计模式(7)——Bridge模式

// “Implementor”
深入浅出设计模式(7)——Bridge模式
abstract class Implementor
深入浅出设计模式(7)——Bridge模式深入浅出设计模式(7)——Bridge模式
深入浅出设计模式(7)——Bridge模式 {

深入浅出设计模式(7)——Bridge模式   
// Methods
深入浅出设计模式(7)——Bridge模式
   abstract public void Operation();
深入浅出设计模式(7)——Bridge模式 }

深入浅出设计模式(7)——Bridge模式
深入浅出设计模式(7)——Bridge模式

// “RefinedAbstraction”
深入浅出设计模式(7)——Bridge模式
class RefinedAbstraction : Abstraction
深入浅出设计模式(7)——Bridge模式深入浅出设计模式(7)——Bridge模式
深入浅出设计模式(7)——Bridge模式 {

深入浅出设计模式(7)——Bridge模式   
// Methods
深入浅出设计模式(7)——Bridge模式
   override public void Operation()
深入浅出设计模式(7)——Bridge模式深入浅出设计模式(7)——Bridge模式   
深入浅出设计模式(7)——Bridge模式 {

深入浅出设计模式(7)——Bridge模式      implementor.Operation();
深入浅出设计模式(7)——Bridge模式    }


深入浅出设计模式(7)——Bridge模式 }

深入浅出设计模式(7)——Bridge模式
深入浅出设计模式(7)——Bridge模式

// “ConcreteImplementorA”
深入浅出设计模式(7)——Bridge模式
class ConcreteImplementorA : Implementor
深入浅出设计模式(7)——Bridge模式深入浅出设计模式(7)——Bridge模式
深入浅出设计模式(7)——Bridge模式 {

深入浅出设计模式(7)——Bridge模式   
// Methods
深入浅出设计模式(7)——Bridge模式
   override public void Operation()
深入浅出设计模式(7)——Bridge模式深入浅出设计模式(7)——Bridge模式   
深入浅出设计模式(7)——Bridge模式 {

深入浅出设计模式(7)——Bridge模式      Console.WriteLine(
ConcreteImplementorA Operation );
深入浅出设计模式(7)——Bridge模式    }

深入浅出设计模式(7)——Bridge模式 }

深入浅出设计模式(7)——Bridge模式
深入浅出设计模式(7)——Bridge模式

// “ConcreteImplementorB”
深入浅出设计模式(7)——Bridge模式
class ConcreteImplementorB : Implementor
深入浅出设计模式(7)——Bridge模式深入浅出设计模式(7)——Bridge模式
深入浅出设计模式(7)——Bridge模式 {

深入浅出设计模式(7)——Bridge模式   
// Methods
深入浅出设计模式(7)——Bridge模式
   override public void Operation()
深入浅出设计模式(7)——Bridge模式深入浅出设计模式(7)——Bridge模式   
深入浅出设计模式(7)——Bridge模式 {

深入浅出设计模式(7)——Bridge模式      Console.WriteLine(
ConcreteImplementorB Operation );
深入浅出设计模式(7)——Bridge模式    }

深入浅出设计模式(7)——Bridge模式 }

深入浅出设计模式(7)——Bridge模式
深入浅出设计模式(7)——Bridge模式深入浅出设计模式(7)——Bridge模式

// /// <summary>
深入浅出设计模式(7)——Bridge模式
/// Client test
深入浅出设计模式(7)——Bridge模式
/// </summary>
深入浅出设计模式(7)——Bridge模式 public class Client
深入浅出设计模式(7)——Bridge模式深入浅出设计模式(7)——Bridge模式
深入浅出设计模式(7)——Bridge模式 {

深入浅出设计模式(7)——Bridge模式   
public static void Main( string [] args )
深入浅出设计模式(7)——Bridge模式深入浅出设计模式(7)——Bridge模式   
深入浅出设计模式(7)——Bridge模式 {

深入浅出设计模式(7)——Bridge模式      Abstraction abstraction
= new RefinedAbstraction();
深入浅出设计模式(7)——Bridge模式
深入浅出设计模式(7)——Bridge模式     

// Set implementation and call
深入浅出设计模式(7)——Bridge模式
     abstraction.Implementor = new ConcreteImplementorA();
深入浅出设计模式(7)——Bridge模式      abstraction.Operation();
深入浅出设计模式(7)——Bridge模式
深入浅出设计模式(7)——Bridge模式     


// Change implemention and call
深入浅出设计模式(7)——Bridge模式
     abstraction.Implementor = new ConcreteImplementorB();
深入浅出设计模式(7)——Bridge模式      abstraction.Operation();
深入浅出设计模式(7)——Bridge模式    }


深入浅出设计模式(7)——Bridge模式 }

四、 调制解调器问题

感觉《敏捷软件开发-原则、模式与实践》中关于Bridge模式的例子很好。(《Java与模式》一书33章的对变化的封装一节也写得很不错,推荐大家读一读。它深入的阐述了《Design Patterns Explained》一书中”1)Design to interfaces. 2)Favor composition over inheritance. 3)Find what varies and encapsulate it”的三个观点。)。

深入浅出设计模式(7)——Bridge模式

如图所示,有大量的调制解调器客户程序在使用Modem接口。Modem接口被几个派生类HayesModem、USRoboticsModem和 EarniesModem实现。它很好地遵循了OCP、LSP和DIP。当增加新种类的调制解调器时,调制解调器的客户程序不会受影响。

假定这种情形持续了几年,并有许多调制解调器的客户程序都在使用着Modem接口。现出现了一种不拨号的调制解调器,被称为专用调制解调器。它们位于一条专用连接的两端。有几个新应用程序使用这些专用调制解调器,它们无需拨号。我们称这些使用者为DedUser。但是,客户希望当前所有的调制解调器客户程序都可以使用这些专用调制解调器。他们不希望去更改许许多多的调制解调器客户应用程序,所以完全可以让这些调制解调器客户程序去拨一些假 (dummy)电话号码。

如果能选择的话,我们会把系统的设计更改为下图所示的那样。

深入浅出设计模式(7)——Bridge模式

我们把拨号和通信功能分离为两个不同的接口。原来的调制解调器实现这两个接口,而调制解调器客户程序使用这两个接口。DedUser只使用 Modem接口,而DedicateModem只实现Modem接口。但这样做会要求我们更改所有的调制解调器客户程序–这是客户不允许的。

一个可能的解决方案是让DedicatedModem从Modem派生并且把dial方法和hangup方法实现为空,就像下面这样:

深入浅出设计模式(7)——Bridge模式

几个月后,已经有了大量的DedUser,此时客户提出了一个新的更改。为了能拨国际电话号码、信用卡电话、PIN标识电话等等,必修对现有dial中使用char[10]存储号码改为能够拨打任意长度的电话号码。

显然,所有的调制解调器客户程序都必须更改。客户同意了对调制解调器客户程序的更改,因为他们别无选择。糟糕的是,现在必须要去告诉DedUser的编写者,他们必须要更改他们的代码!你可以想象他们听到这个会有多高兴。本来他们是不用调用dial的。

这就是许多项目都会具有的那种有害的混乱依赖关系。系统某一部分中的一个杂凑体(kludge)创建了一个有害的依赖关系,最终导致系统中完全无关的部分出现问题。

如果使用ADAPTER模式解决最初的问题的话,就可以避免这个严重问题。如图:

深入浅出设计模式(7)——Bridge模式

请注意,杂凑体仍然存在。适配器仍然要模拟连接状态。然而,所有的依赖关系都是从适配器发起的。杂凑体和系统隔离,藏身于几乎无人知晓的适配器中。

BRIDGE模式

看待这个问题,还有另外一个方式。现在,出现了另外一种切分Modem层次结构的方式。如下图:

深入浅出设计模式(7)——Bridge模式

这不是一个理想的结构。每当增加一款新硬件时,就必须创建两个新类–一个针对专用的情况,一个针对拨号的情况。每当增加一种新连接类型时,就必须创建3个新类,分别对应3款不同的硬件。如果这两个自由度根本就是不稳定的,那么不用多久,就会出现大量的派生类。

在类型层次结构具有多个自由度的情况中,BRIDGE模式通常是有用的。我们可以把这些层次结构分开并通过桥把它们结合到一起,而不是把它们合并起来。如图:

深入浅出设计模式(7)——Bridge模式

我们把调制解调器类层次结构分成两个层次结构。一个表示连接方法,另一个表示硬件。

这个结构虽然复杂,但是很有趣。它的创建不会影响到调制解调器的使用者,并且还完全分离了连接策略和硬件实现。 ModemConnectController的每个派生类代表了一个新的连接策略。在这个策略的实现中可以使用sendlmp、receivelmp、 diallmp和hanglmp。新imp方法的增加不会影响到使用者。可以使用ISP来给连接控制类增加新的接口。这种做法可以创建出一条迁移路径,调制解调器的客户程序可以沿着这条路径慢慢地得到一个比dial和hangup层次更高的API。

 

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/128293.html

(0)
上一篇 2025-09-01 18:20
下一篇 2025-09-01 18:26

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信