注:本文不属于原创,而是根据原文重新整理,原文是:我给媳妇解释设计模式:第一部分


设计模式不是基于理论发明的。相反,总是先有问题场景,再基于需求和情景不断演化设计方案,最后把一些方案标准化成“模式”。所以,我们讨论每一个设计模式时,要尽量用生活中的真实问题来理解和分析。然后尝试一步步地阐述设计,并以一个能匹配某些模式的设计收尾。

设计问题与解决方案

先让我们考虑一下下面的情况:
      我们的家里都有家用电器(比如电灯和风扇),他们都是由开关控制。 任何时候,你都可以在不改变其他东西的情况下做一些事。你可以在不更换开关的情况下换掉灯泡,也可以在不接触灯泡或者风扇的情况下更换开关,甚至可以在不接触开关的情况下,把灯泡和风扇的开关互换。

   

  灯泡和风扇

      

  不同类型的开关

当不同的事物联系到一起时,他们应该在一个可以变更或者可以替换的系统中以便不相互影响,或者影响尽可能的小。这样让你更为方便、成本最小地去管理你的系统。可以想象,如果你要换一个你房间里的灯泡得要求你把开关也换了,你会考虑在你房子里使用这样的一个系统吗? 当然不会。 现在,让我们想一下电灯或者电风扇是怎样和开关联系起来以便更换其中一个而不会影响到其他的。当然是电线啦。 是电线以及其他的电工手段把电灯/电风扇与开关连接起来。我们可以把这概括为沟通不同系统的桥梁。基本思想是,一个事物不能直接连接另一个事物。当然,他们能够通过一些桥梁或接口连接起来。在软件世界里,我们称之为“松耦合”。
      现在,我们来尝试理解一些类似电灯/电风扇与开关类似的关键问题,同时尝试理解是怎样设计和关联它们的。
      在我们的列子里,有一些开关,这些类似普通的开关、有不同的花式开关可能有不同的种类,但是,一般情况下,他们就是开关。同时,每个开关都能开和关。
      这样的话,我们就会得到如下的Switch基类:

 public class Switch
{
public void On()
{
// 开关有一个“开”的按钮
}
public void Off()
{
// 开关有一个“关”的按钮
}
}

同时,我们可能也需要一些特定类型的开关,譬如正常的开关、不同花式的开关等等。同样的我们扩展Switch类来实现FancySwitch和NormalSwitch:

 public class NormalSwitch : Switch
{
} public class FancySwitch : Switch
{
}

这两个特定的开关类可能用于它们自己特有的行为和特征,但是到目前为止,我们还是保持它们现在的简单形式。

现在,如何处理风扇和灯呢?
      按照面向对象设计原则中的封闭原则,我认为我们需要试着在任何可能的地方做抽象处理。
      电扇和电灯情况有点不一样,它们两个不是同一种东西。对于不同的开关,我们可以用同一个基本的Switch类,但对于电扇和电灯就不大合适了,感觉用接口会更合适一点。因为,从大体上讲,它们都算是电器,那么我们可以就定义一个接口: IElectricalEquipment,用它来抽象电扇和电灯。
      那么,所有电器都有一些共性,可以被打开和关闭。那么这个接口就可以是:

 public interface IElectricalEquipment
{
void PowerOn(); // 每个电器都能够被打开
void PowerOff(); // 每个电器都能够被关闭
}

好了,现在我们还缺一座桥。在现实世界里,桥是电线。在对象的世界里,开关知道怎么开关电器,电器需要用某种方式跟开关连起来。可这里没有电线,我们唯一有的,是封装。

开关并不知道电扇和电灯的存在。它只知道它可以打开或关闭某个电器IElectricalEquipment。那么,也就是说每个Switch应该拥有一个IElectricalEquipment实例。
      这里,被封装的实例,也就是IElectricalEquipment,就是这座桥。好,我们来修改一下Switch类,让它把电器封装进去:

 public class Switch
{
public IElectricalEquipment equipment
{
get;
set;
}
public void On()
{
// 开关有一个打开的按钮
}
public void Off()
{
// 开关有一个关闭的按钮
}
}

接下来我再定义真正的电器吧。电扇和电灯,总体上都是电器,所以它们应该实现IElectricalEquipment接口。

电扇类:

 public class Fan : IElectricalEquipment
{
public void PowerOn()
{
Console.WriteLine("Fan is on");
}
public void PowerOff()
{
Console.WriteLine("Fan is off");
}
}

电灯类:

 public class Light : IElectricalEquipment
{
public void PowerOn()
{
Console.WriteLine("Light is on");
}
public void PowerOff()
{
Console.WriteLine("Light is off");
}
}

很好。现在该是接上开关的时候了。开关在打开和关闭的时候,必须能打开和关闭它所连接的电器。

也就是说:
      • 当按下开关的打开按钮时,必须打开连接的电器。
      • 当按下开关的关闭按钮时,必须关闭连接的电器。
      我们想要的功能基本上是这个样子:

 static void Main(string[] args)
{
//我们有一些电器,比如风扇、电灯等,因此我们首先要创建它们
IElectricalEquipment fan = new Fan();
IElectricalEquipment light = new Light();
//我们也有一些开关,同样需要创建它们
Switch fancySwitch = new FancySwitch();
Switch normalSwitch = new NormalSwitch(); //让我们将电扇和电扇开关连接起来
fancySwitch.equipment = fan; //现在开关对应了一个设备(电扇),因此可以开关设备。
//下面这个操作将打开电扇
//当然,在开关的这个 On() 方法里面我们必须打开电器。
fancySwitch.On();
//下面这个操作将关闭电扇
fancySwitch.Off(); //现在我们将电灯与风扇的开关连接起来
fancySwitch.equipment = light;
fancySwitch.On(); // 现在它将打开电灯
fancySwitch.Off(); // 现在它将关闭电灯
}

那么,开关的On()方法应该调用电器的TurnOn()方法,而它的Off()方法应该调用电器的TurnOff()方法,Switch类应该是这个样子:

 public class Switch
{
public void On()
{
Console.WriteLine("Switch on the equipment");
equipment.PowerOn();
}
public void Off()
{
Console.WriteLine("Switch off the equipment");
equipment.PowerOff();
}
}

这个电扇显示是可以换开关的。而且,反过来也是可以换的,可以不修改电扇和电灯,直接更换开关,例如,我们可以把电灯的开关从FancySwitch换成NormalSwitch:

 normalSwitch.equipment = light;
normalSwitch.On(); //It should turn on the Light now
normalSwitch.Off(); //It should be turn off the Light now

看到没,我们可以在不影响任何一方的情况下,改变另一方。这个设计看起来很不错,而且相当的优雅。其实四人帮(GoF)管这个设计叫桥接模式。

一般来说,两个系统不应该直接地互相联接和依赖。相反,他们应该通过抽象来联接或依赖(参见依赖倒置和开闭原则),这样它们就是松耦合的,我们就可以在必要时轻松地修改实现,而不对系统的其它部分造成太大影响。

桥接模式的定义

我们来看一下桥接模式的定义吧:

    “把抽象和实现解耦,使得它们可以独立地变化”

桥接模式的类图结构如下:


      在我们的例子里,Abstraction是基础的Switch类,RefinedAbstraction是某个具体的开关类(FancySwitch和NormalSwitch),Implementor是IElectricalEquipment接口,ConcreteImplementorA和ConcreteImplementorB分别是Fan和Light类。
      桥接模式是所有面向对象设计模式的基础。因为:
      • 它能教你如何抽象地思维,这可是OO设计模式的关键。
      • 它实现了基本的OOD原则。
      • 它很好理解。
      • 如果能正确地理解它,学习其它模式就易如反掌了。

 

设计模式之桥接模式(Bridge)的更多相关文章

  1. 乐在其中设计模式(C#) - 桥接模式(Bridge Pattern)

    原文:乐在其中设计模式(C#) - 桥接模式(Bridge Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 桥接模式(Bridge Pattern) 作者:webabcd 介绍 ...

  2. 【设计模式】桥接模式 Bridge Pattern

    开篇还是引用吕振宇老师的那篇经典的文章<设计模式随笔-蜡笔与毛笔的故事>.这个真是太经典了,没有比这个例子能更好的阐明桥接模式了,这里我就直接盗来用了. 现在市面上卖的蜡笔很多,各种型号, ...

  3. python 设计模式之桥接模式 Bridge Pattern

    #写在前面 前面写了那么设计模式了,有没有觉得有些模式之间很类似,甚至感觉作用重叠了,模式并不是完全隔离和独立的,有的模式内部其实用到了其他模式的技术,但是又有自己的创新点,如果一味地认为每个模式都是 ...

  4. 二十四种设计模式:桥接模式(Bridge Pattern)

    桥接模式(Bridge Pattern) 介绍将抽象部分与它的实现部分分离,使它们都可以独立地变化. 示例有一个Message实体类,对它的操作有Insert()和Get()方法,现在使这些操作的抽象 ...

  5. [设计模式] 7 桥接模式 bridge

    #include<iostream> using namespace std; class AbstractionImp { public: virtual ~AbstractionImp ...

  6. 设计模式之桥接模式(Bridge)--结构模型

    1.意图 将抽象部分与它的实现部分分离,使它们可以独立地变化. 2.适用性 你不希望在抽象和它的实现部分之间有一个固定的绑定关系. 类的抽象与它的实现都应该可以通过子类的方式加以扩展. 抽象部分与实现 ...

  7. 设计模式 笔记 桥接模式 Bridge

    //---------------------------15/04/15---------------------------- //Bridge 桥接模式----对象结构型模式 /* 1:意图:将 ...

  8. 设计模式之桥接模式(Bridge)

    桥接模式与原理:将抽象部分与实现部分分离,使它们都可以独立的变化.最终的结果表现在实现类中.两者之间属于等价关系,即实现部分和抽象部分可以相互交换. 代码如下 #include <iostrea ...

  9. 结构型设计模式之桥接模式(Bridge)

    结构 意图 将抽象部分与它的实现部分分离,使它们都可以独立地变化. 适用性 你不希望在抽象和它的实现部分之间有一个固定的绑定关系.例如这种情况可能是因为,在程序运行时刻实现部分应可以被选择或者切换. ...

  10. 【设计模式】—— 桥接模式Bridge

    前言:[模式总览]——————————by xingoo 模式意图 这个模式使用的并不多,但是思想确实很普遍.就是要分离抽象部分与实现部分. 实现弱关联,即在运行时才产生依赖关系. 降低代码之间的耦合 ...

随机推荐

  1. 使用magick.net将pdf转换为图片

    现在手上有个需求是要将pdf转换为一页一页的image.最开始找到的是pdfbox来处理pdf的.在pdfbox.apache.org的官网首页写了一句'convert you pdfs to ima ...

  2. ODAC(V9.5.15) 学习笔记(十六)直接访问模式

    直接访问模式(Direct mode)是ODAC最大的特色之一,即不需要安装Oracle客户端,ODAC越过了OCI(Oracle Call Interface ),使用TCP/IP协议就可以直接与O ...

  3. SharePoint 2013中以其他用户身份登录的WebPart(免费下载)

    在SharePoint 2013中微软并没有提供在SharePoint 2010中以其他用户身份登录的菜单,这对一般用户影响不大,但对于系统管理员或测试人员或特定人员(如在OA系统中的文员或秘书,常常 ...

  4. [转]Handy adb commands for Android

    转自:http://www.growingwiththeweb.com/2014/01/handy-adb-commands-for-android.html View connected devic ...

  5. 树莓派 LED+蜂鸣+声音传感器+红外模块组合打造声控/红外控制LED

    昨天搞了控制LED,玩了第一个,剩下的就感觉很简单了,这里记录一下 先来几张照片 玩了蜂蜜模块才发现规律,一般这种模块,都会有三个针脚,VCC(3.3V或5V供电输出针脚).GNC(对应GPIO针脚的 ...

  6. Nginx+Keepalived实现站点高可用

    http://seanlook.com/2015/05/18/nginx-keepalived-ha/ http://blog.csdn.net/conquer0715/article/details ...

  7. Sql触发器模板

    触发器是一种特殊类型的存储过程,它不同于之前的我们介绍的存储过程. 触发器主要是通过事件进行触发被自动调用执行的.而存储过程可以通过存储过程的名称被调用. SQL Server 2005中触发器可以分 ...

  8. repo: 创建local manifest以及如何添加app到CM/Android build系统中

    The local manifest Creating a local manifest allows you to customize the list of repositories on you ...

  9. SpringMVC Controller 返回值的可选类型

    spring mvc 支持如下的返回方式:ModelAndView, Model, ModelMap, Map,View, String, void. ModelAndView @RequestMap ...

  10. 关于js中的回收机制,通俗版

    在前面的几篇文章中,我讲解过了js中的回收机制,但是对于当时的我来说,我自己对回收机制的这个概念也有些懵懵懂懂,现在对回收机制有了更深入的理解,所以特此发布此文给于总结,也好加深记忆. 如果你想学习闭 ...