概述

在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度?这就要使用Bridge模式。

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

意图

将抽象部分与实现部分分离,使它们都可以独立的变化。[GOF 《设计模式》],这里的抽象和实现并不一定是同一层次的概念,例如数据库操作可以归结为“增加、删除和修改”。很多业务过程都是通过对数据库的操作实现的,例如“库存管理”中的“入库”,这个业务动作的软件实现可以描述为“在库存表中增加一条记录”,而“入库”和“插入记录”处于不同的业务层次。

<Design Pattern>结构图

图1 Bridge模式结构图

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

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

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

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

生活中的例子

桥接模式将抽象部分与它的实现分离,使它们能够独立地变化。一个普通的开关控制的电灯、电风扇等等,都是桥接的例子。开关的目的是将设备打开或关闭。实际的开关可以是简单的双刀拉链开关,也可以是调光开关。

图2 使用电子开关例子的桥接对象图

形象比喻

小时候我们都用蜡笔画画,一盒蜡笔12种颜色。一开始我都是用最小号的蜡笔画个太阳公公、月亮婆婆足够了。后来开始画一些抽象派的作品,就得换中号的了,要不然画个背景都要描半天,好一盒中号的也是12种颜色。再后来我开始转向豪放派,中号就有些捉襟见肘了,只好换大号的了,好一盒大号的也只有12种颜色。你看,像我这样不太出名的画家就需要36种画笔,哇,太麻烦了。但是据我观察,另一些比我出名的画家倒是没有这么多笔,他们只有几把刷子和一些颜料,这样就解决了蜡笔的“种类爆炸”问题。如下图所示:


我要用36种蜡笔

齐白石老先生只用3种毛笔和12种颜料

示例用例图

控制程序开和关,与哪种类型的控制,如:电视,灯等等.正好符合桥接模式,用例图如下:

代码设计

先创建CntrlControl.cs:

    /// <summary>/// control class/// </summary>public abstract class CntrlControl {/// <summary>/// turn on/// </summary>/// <returns></returns>public abstract string TurnOn();/// <summary>/// turn off/// </summary>/// <returns></returns>public abstract string TurnOff();}

再创建Lamp.cs:

    public  class Lamp:CntrlControl{public override string TurnOn(){return "灯亮了";}public override string TurnOff(){return "灯关了";}}

再创建Television.cs:

   public  class Television:CntrlControl{public override string TurnOn(){return "电视开了";}public override string TurnOff(){return "电视关了";}}

再创建ControlCenter.cs:

    /// <summary>/// control center/// </summary>public abstract class ControlCenter{private CntrlControl centerControl;public CntrlControl CenterControl{get {return centerControl;}set {centerControl = value;}}public ControlCenter(){ }public ControlCenter(CntrlControl cntrlControl){this.centerControl = cntrlControl;}public abstract string TurnOn();public abstract string TurnOff();}

再创建LampControl.cs:

    public class LampControl:ControlCenter{public override string TurnOn(){return "我房间的灯控制"+ CenterControl.TurnOn();}public override string TurnOff(){return "我房间的灯控制" + CenterControl.TurnOff();}public LampControl(){ }public LampControl(CntrlControl cntrlControl): base(cntrlControl){ }}

再创建TVControl.cs:

    public class TVControl:ControlCenter{public override string TurnOn(){return "客厅的电视控制"+ CenterControl.TurnOn();}public override string TurnOff(){return "客厅的电视控制" + CenterControl.TurnOff();}public TVControl(){ }public TVControl(CntrlControl cntrlControl): base(cntrlControl){ }}

最后再调用:

    public partial class Run : Form{public Run(){InitializeComponent();}private void btnRun_Click(object sender, EventArgs e){//-------------------------------------ControlCenter lampControl = new LampControl(new Lamp());rtbResult.AppendText("节能灯控制开始.\n");rtbResult.AppendText(lampControl.TurnOn() + "\n");rtbResult.AppendText(lampControl.TurnOff() + "\n");rtbResult.AppendText("节能灯控制结束.\n\n\n");ControlCenter tvControl = new TVControl(new Television());rtbResult.AppendText("电视控制开始.\n");rtbResult.AppendText(tvControl.TurnOn() + "\n");rtbResult.AppendText(tvControl.TurnOff() + "\n");rtbResult.AppendText("电视控制结束.\n");//-------------------------------------}}

运行结果如下图:

效果及实现要点

1.Bridge模式使用“对象间的组合关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。

2.所谓抽象和实现沿着各自维度的变化,即“子类化”它们,得到各个子类之后,便可以任意它们,从而获得不同平台上的不同型号。

3.Bridge模式有时候类似于多继承方案,但是多继承方案往往违背了类的单一职责原则(即一个类只有一个变化的原因),复用性比较差。Bridge模式是比多继承方案更好的解决方法。

4.Bridge模式的应用一般在“两个非常强的变化维度”,有时候即使有两个变化的维度,但是某个方向的变化维度并不剧烈——换言之两个变化不会导致纵横交错的结果,并不一定要使用Bridge模式。

5.选择合适的类型作为抽象化角色(第一维度)。

6.抽象化角色和实现化角色通过组合进行关联。

7.抽象和实现不绑定,允许客户端作切换。

适用性

在以下的情况下应当使用桥梁模式:

1.如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的联系。

2.设计要求实现化角色的任何改变不应当影响客户端,或者说实现化角色的改变对客户端是完全透明的。

3.一个构件有多于一个的抽象化角色和实现化角色,系统需要它们之间进行动态耦合。

4.虽然在系统中使用继承是没有问题的,但是由于抽象化角色和具体化角色需要独立变化,设计要求需要独立管理这两者。

5.从代码角度来说,如果类型的继承是处于2个目的(违背单一职责原则)的话可以使用Bridge模式避免过多的子类。

6.从应用角度来说, 如果应用会在多个维度上进行变化,客户端希望两个维度(场景、游戏模式)的对象相对独立,动态耦合(客户端决定哪个场景和哪个游戏模式耦合)的时候可以考虑Bridge模式。

总结

Bridge模式是一个非常有用的模式,也非常复杂,它很好的符合了开放-封闭原则和优先使用对象,而不是继承这两个面向对象原则。

转载于:https://www.cnblogs.com/springyangwc/archive/2011/04/20/2023030.html

步步为营 .NET 设计模式学习笔记 十三、Bridge (桥接模式)相关推荐

  1. 设计模式学习笔记之(桥接模式brid…

    首先桥接模式解决的是抽象和具体实现相分离的问题.想象下这种常见的场景车在路上跑,这是一个行为,但是具体是什么车之什么路上跑就跟具体的使用场景相关联了.比如说可能是宝马车之高速公路上跑,也有可能是 公交 ...

  2. java 设计模式学习笔记十 bridge桥模式

    bridge桥模式 将抽象和行为划分开来,各自独立但能动态结合 抽象的接口 /**  * 咖啡抽象类  *   * @time 下午09:14:27  * @author retacn yue  * ...

  3. 步步为营 .NET 设计模式学习笔记系列总结

    设计模式我从开篇到23种设计模式的讲解总共花了进两个月的时间,其间有很多读者给我提出了很好的建议,同时也指出了我的不足,对此我表示感谢,正是由于很多读者的支持我才能坚持的写到最后.在此表示我真诚的谢意 ...

  4. 设计模式学习笔记——享元(Flyweight)模式

    设计模式学习笔记--享元(Flyweight)模式 @(设计模式)[设计模式, 享元模式, flyweight] 设计模式学习笔记享元Flyweight模式 基本介绍 享元案例 类图 实现代码 Big ...

  5. 设计模式学习笔记——中介者(Mediator)模式

    设计模式学习笔记--中介者(Mediator)模式 @(设计模式)[设计模式, 中介者模式, Mediator] 设计模式学习笔记中介者Mediator模式 基本介绍 中介者案例 类图 实现代码 Me ...

  6. 设计模式学习笔记——单例(Singleton)模式

    设计模式学习笔记--单例(Singleton)模式 @(设计模式)[设计模式, 单例模式, Singleton, 懒汉式, 饿汉式] 设计模式学习笔记单例Singleton模式 基本介绍 单例案例 类 ...

  7. 步步为营 .NET 设计模式学习笔记 一、开篇(设计模式之泡妞二十三招)

    园子里讲设计模式的太多了,最近我也在学设计模式,把我自己练的一些代码整理下,写个.NET设计模式学习笔记来让自己在设计模式的功底更深一层. 记得金庸小说里风清扬教令狐冲的时候,说过独孤九剑的总纲,无招 ...

  8. 设计模式学习笔记--桥梁(Bridge)模式

    写在模式学习之前 什么是设计模式:在我们进行程序设计时,逐渐形成了一些典型问题和问题的解决方案,这就是软件模式:每一个模式描述了一个在我们程序设计中经常发生的问题,以及该问题的解决方案:当我们碰到模式 ...

  9. 设计模式学习笔记--Mediator 中介者模式

    我们知道面向对象应用程序是由一组为了提供某种服务而彼此交互的对象组成.当彼此引用的对象数量比较少时,此时对象之间就为直接交互(点对点).而当对象的数量增加时,这种直接交互会导致对象之间复杂的.混乱的引 ...

最新文章

  1. 常用获取线程基本信息的方法(新手专属)
  2. WPF特效-拼图游戏
  3. Visual Studio 10将面世 微软走得太快?
  4. Go1.18 新特性:高效复制,strings, bytes 库新增 Clone 功能
  5. 虹软sdk 服务器运行 错误码94212 解决方案
  6. 名片夹android布局代码,Android自定义布局实现仿qq侧滑部分代码
  7. 手机运行内存6+128跟8+128有什么区别?
  8. 【语音去噪】基于matlab GUI谱减法+维纳滤波语音去噪(带面板+信噪比)【含Matlab源码 1661期】
  9. 如何拦截Windows键而不屏蔽它参与的组合键(如win+d等)
  10. Retinex理论,单尺度Retinex、多尺度Retinex(MSR)、带颜色恢复的多尺度 Retinex(MSRCR)原理
  11. 程序员 写作_如何经常写作可以使您成为更好的程序员
  12. 【JS30-Wes Bos】实时显示的时钟网页 02
  13. 青少年CTF--misc部分题解
  14. 带你了解什么是Nginx(实操反向代理-负载均衡)
  15. C# Winform 计算机原理模型机的设计——带超前进位加法器
  16. 37互娱,2019秋招提前批,web后端工程师
  17. 数据处理--图片像素点聚类
  18. 调频广播信号监测监播系统(广播电台调频广播监控系统)解决方案
  19. 力扣第314场周赛补题
  20. PHP 代码页面操作

热门文章

  1. python和按键精灵自动化测试_按键精灵对APP自动化测试(下)
  2. python exe是什么_[Python] [转] python.exe和pythonw.exe的区别(区分.py、.pyw、.pyc文件)...
  3. java库存导出_java生成导出excle文件
  4. base64 不一致_这几项超好用的云开发扩展能力,别说你还不知道!
  5. mysql 数据趋势,2019年8月全球数据库流行度排行--oracle、mysql增长趋势明显
  6. mysql gitd 数据结构同步失败_Mysql5.7版本Gtid复制出现不同步的情况
  7. java web博客系统_JavaWeb之博客系统(五)
  8. 这几种程序员前途无量!你在其中吗?
  9. 印度程序员为什么牛掰之ISAS.激发人的兴趣.探索精神.
  10. jrebel不能使用ajax,Jrebel不生效的原因和解决办法