设计模式之桥接模式(Bridge)
注:本文不属于原创,而是根据原文重新整理,原文是:我给媳妇解释设计模式:第一部分
设计模式不是基于理论发明的。相反,总是先有问题场景,再基于需求和情景不断演化设计方案,最后把一些方案标准化成“模式”。所以,我们讨论每一个设计模式时,要尽量用生活中的真实问题来理解和分析。然后尝试一步步地阐述设计,并以一个能匹配某些模式的设计收尾。
设计问题与解决方案
先让我们考虑一下下面的情况:
我们的家里都有家用电器(比如电灯和风扇),他们都是由开关控制。 任何时候,你都可以在不改变其他东西的情况下做一些事。你可以在不更换开关的情况下换掉灯泡,也可以在不接触灯泡或者风扇的情况下更换开关,甚至可以在不接触开关的情况下,把灯泡和风扇的开关互换。
灯泡和风扇
不同类型的开关
当不同的事物联系到一起时,他们应该在一个可以变更或者可以替换的系统中以便不相互影响,或者影响尽可能的小。这样让你更为方便、成本最小地去管理你的系统。可以想象,如果你要换一个你房间里的灯泡得要求你把开关也换了,你会考虑在你房子里使用这样的一个系统吗? 当然不会。 现在,让我们想一下电灯或者电风扇是怎样和开关联系起来以便更换其中一个而不会影响到其他的。当然是电线啦。 是电线以及其他的电工手段把电灯/电风扇与开关连接起来。我们可以把这概括为沟通不同系统的桥梁。基本思想是,一个事物不能直接连接另一个事物。当然,他们能够通过一些桥梁或接口连接起来。在软件世界里,我们称之为“松耦合”。
现在,我们来尝试理解一些类似电灯/电风扇与开关类似的关键问题,同时尝试理解是怎样设计和关联它们的。
在我们的列子里,有一些开关,这些类似普通的开关、有不同的花式开关可能有不同的种类,但是,一般情况下,他们就是开关。同时,每个开关都能开和关。
这样的话,我们就会得到如下的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)的更多相关文章
- 乐在其中设计模式(C#) - 桥接模式(Bridge Pattern)
原文:乐在其中设计模式(C#) - 桥接模式(Bridge Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 桥接模式(Bridge Pattern) 作者:webabcd 介绍 ...
- 【设计模式】桥接模式 Bridge Pattern
开篇还是引用吕振宇老师的那篇经典的文章<设计模式随笔-蜡笔与毛笔的故事>.这个真是太经典了,没有比这个例子能更好的阐明桥接模式了,这里我就直接盗来用了. 现在市面上卖的蜡笔很多,各种型号, ...
- python 设计模式之桥接模式 Bridge Pattern
#写在前面 前面写了那么设计模式了,有没有觉得有些模式之间很类似,甚至感觉作用重叠了,模式并不是完全隔离和独立的,有的模式内部其实用到了其他模式的技术,但是又有自己的创新点,如果一味地认为每个模式都是 ...
- 二十四种设计模式:桥接模式(Bridge Pattern)
桥接模式(Bridge Pattern) 介绍将抽象部分与它的实现部分分离,使它们都可以独立地变化. 示例有一个Message实体类,对它的操作有Insert()和Get()方法,现在使这些操作的抽象 ...
- [设计模式] 7 桥接模式 bridge
#include<iostream> using namespace std; class AbstractionImp { public: virtual ~AbstractionImp ...
- 设计模式之桥接模式(Bridge)--结构模型
1.意图 将抽象部分与它的实现部分分离,使它们可以独立地变化. 2.适用性 你不希望在抽象和它的实现部分之间有一个固定的绑定关系. 类的抽象与它的实现都应该可以通过子类的方式加以扩展. 抽象部分与实现 ...
- 设计模式 笔记 桥接模式 Bridge
//---------------------------15/04/15---------------------------- //Bridge 桥接模式----对象结构型模式 /* 1:意图:将 ...
- 设计模式之桥接模式(Bridge)
桥接模式与原理:将抽象部分与实现部分分离,使它们都可以独立的变化.最终的结果表现在实现类中.两者之间属于等价关系,即实现部分和抽象部分可以相互交换. 代码如下 #include <iostrea ...
- 结构型设计模式之桥接模式(Bridge)
结构 意图 将抽象部分与它的实现部分分离,使它们都可以独立地变化. 适用性 你不希望在抽象和它的实现部分之间有一个固定的绑定关系.例如这种情况可能是因为,在程序运行时刻实现部分应可以被选择或者切换. ...
- 【设计模式】—— 桥接模式Bridge
前言:[模式总览]——————————by xingoo 模式意图 这个模式使用的并不多,但是思想确实很普遍.就是要分离抽象部分与实现部分. 实现弱关联,即在运行时才产生依赖关系. 降低代码之间的耦合 ...
随机推荐
- JS实现IOS风格对话框 jquery / zepto
Alert alert("这个是一个alert弹窗"); Alert 自定义参数 alert({ content: "自定义alert弹窗", btnText: ...
- SPF 简介
SPF 简介 摘要: SPF 是发送方策略框架 (Sender Policy Framework) 的缩写,希望能成为一个防伪标准,来防止伪造邮件地址.这篇文章对 SPF 进行了简单介绍,并介绍了它的 ...
- POJ 2785 4 Values whose Sum is 0
4 Values whose Sum is 0 Time Limit: 15000MS Memory Limit: 228000K Total Submissions: 13069 Accep ...
- 高效的INSERT INTO SELECT和SELECT INTO
1.INSERT INTO SELECT,目标表必须存在,才可批量插入 INSERT INTO 目标表Table(field1,field2,field2,...) SELECT value1,val ...
- 在linux安装mysql,并设置远程访问
1.查看系统有没有安装mysql. vpm -qa mysql 发现有删除:rpm -e mysql(rpm -e --nodeps mysql) 2.下载数据库 mysql-standard-5.0 ...
- 树莓派 HC-SRO4超声波测距模块的使用
先上个图 这个模块的针脚跟之前玩的那三个有所区别,除了VCC和GND两个针脚,还多了两个Trig和Echo针脚,分别是输出和输入,Trig我接的是20针脚,Echo是21 该模块的工作原理为,先向TR ...
- CSS3实现倒计时
CSS3实现倒计时小程序,界面如下: 代码如下: <style> body,html{ margin:0px; height:100%; } body{background: #000; ...
- 解决rspec 生成报告时报utf-8错误的方法
找到gems\1.9.1\gems\rspec-core-2.14.3\lib\rspec\core\formatters\snippet_extractor.rb文件中的第27行: 在这边记录一下, ...
- 导出excel和PDF小结 vba
最近接触了一个关于Access工具的项目,所以整理下需要使用的方法. 功能要求简介: 1.将数据表中的数据导出到excel和PDF 2.并根据某个字段名称分sheet输出. 3.无模板方式 方案简介: ...
- centos mongodb安装及简单实例
1.创建目录并设置写权限的操作如下: $mkdir -p /data/db (创建目录和必要的父目录,若父目录不存在则先创建父目录再创建子目录) $ chown -R $usergroup:$user ...