Bridge桥接模式.ppt
桥接模式(Bridge)

桥接模式(Bridge)1 场景问题1.1 发送提示消息考虑这样一个实际的业务功能:发送提示消息。
基本上所有带业务流程处理的系统都会有这样的功能,比如某人有新的工作了,需要发送一条消息提示他。
从业务上看,消息又分成普通消息、加急消息和特急消息多种,不同的消息类型,业务功能处理是不一样的,比如加急消息是在消息上添加加急,而特急消息除了添加特急外,还会做一条催促的记录,多久不完成会继续催促。
从发送消息的手段上看,又有系统内短消息、手机短消息、邮件等等。
现在要实现这样的发送提示消息的功能,该如何实现呢?1.2 不用模式的解决方案1:实现简化版本先考虑实现一个简单点的版本,比如:消息先只是实现发送普通消息,发送的方式呢,先实现系统内短消息和邮件。
其它的功能,等这个版本完成过后,再继续添加,这样先把问题简单化,实现起来会容易一点。
(1)由于发送普通消息会有两种不同的实现方式,为了让外部能统一操作,因此,把消息设计成接口,然后由两个不同的实现类,分别实现系统内短消息方式和邮件发送消息的方式。
此时系统结构如图1所示:图1 简化版本的系统结构示意图下面看看大致的实现示意。
(2)先来看看消息的统一接口,示例代码如下:Java代码1./**2. * 消息的统一接口3. */4.public interface Message {5. /**6. * 发送消息7. * @param message 要发送的消息内容8. * @param toUser 消息发送的目的人员9. */10. public void send(String message,String toUser);11.}(3)再来分别看看两种实现方式,这里只是为了示意,并不会真的去发送Email 和站内短消息,先看站内短消息的方式,示例代码如下:Java代码1./**2. * 以站内短消息的方式发送普通消息3. */4.public class CommonMessageSMS implements Message{5. public void send(String message, String toUser) {6. System.out.println("使用站内短消息的方式,发送消息'"7.+message+"'给"+toUser);8. }9.}同样的,实现以Email的方式发送普通消息,示例代码如下:Java代码1./**2. * 以Email的方式发送普通消息3. */4.public class CommonMessageEmail implements Message{5. public void send(String message, String toUser) {6. System.out.println("使用Email的方式,发送消息'"7.+message+"'给"+toUser);8. }9.}2:实现发送加急消息上面的实现,看起来很简单,对不对。
4.2. 桥接(bridge)模式

需求变化
如果用户要求支持另一种形状——圆形。同时集合对象 不希望知道Rectangle和Circle之间的差异。 可以简单地扩展前面使用的方法,在类体系中再增加一 层。只需要增加一个名叫Shape的新类,并从中派生出 Rectangle类和Circle类。这样,Client对象可以只引用 Shape对象,而不必考虑自己拥有的究竟是Shape类的 哪种派生类。
桥接模式
系统同时只处理3 系统同时只处理3个对象
Rectangle对象或 Circle对象,但Client 对象不知道它究竟是 哪一个。
V1Drawing对象或 V2Drawing对象, 但Shape对象无需 知道它究竟是哪一 个。
这必须是类型适 当的对象,但使 用它的Drawing 对象知道它的具 体类型。ቤተ መጻሕፍቲ ባይዱ
桥模式的推导
每个画图程序为Shape类的每个派生类实现其细节—— 从Rectangle类派生出一个DP1的版本和一个DP2的版 本,从Circle类也派生出一个DP1的版本和一个DP2的 版本。
不足
如果拥有另一套画图程序(实现上的另一种变化)会 发生什么?将拥有六种不同类型的Shape派生类(两 个Shape概念乘以三套画图程序)。 如果再获得另一个类型的Shape(另一个概念上的变 化)会发生什么?将拥有九种不同类型的Shape派生 类(三个Shape概念乘以三套画图程序)。
自然的做法
通过引入一个Rectangle 抽象类,利用了这一事 实:不同的Rectangle派 生类之间唯一的差异是如 何实现drawLine方法。 V1Rectangle类的实现方 式是:保存一个DP1对象 的引用,使用DP1对象的 draw_a_line方法。 V2Rectangle类的实现方 法是:保存一个DP2对象 的引用,使用这个对象的 drawline方法。
第14章桥梁模式(Bridge)

设计原则:组合优先 • 继承复用的优点
– 可以很容易的修改或扩展父类的实现
设计原则:组合优先 • 继承复用的缺点
– 继承破坏封装,因为父类的实现细节完全暴露 给子类(白盒复用) – 父类的实现发生改变,则子类必受牵连 – 继承是静态的,不能在运行时发生改变,不灵 活
设计原则:组合优先 • 组合复用的优点
– 变化点3:鸟类的行为——游泳
设计原则 “使变化点和不变点独立开来” “鸟类”和“行为”什么关系?
– 鸟类拥有行为 – 鸟类行为的具体实现,委托“行为”类来完成
• 鸟儿拥有飞、游泳的行为
• 比如增加一种鸟类“鹅”,相应的要增加 一种游泳的行为“红掌拨清波”
– – – – 只需要增加一个鸟类的子类“鹅” 增加一个游泳的行为“红掌拨清波” 设置“鹅”的飞翔行为为“飞不起来” 设置“鹅”的游泳行为为“红掌拨清波”
public abstract class Implementor { public abstract void OperationImp(); }
public class ConcreteImplementorA extends Implementor { public void OperationImp() { System.out.println("ConcreteImplementorA Operation"); }
Code – 2 of 2 (Implementor)
public class ItalianMealImp implements MealImp { public void getAppetizer() { System.out.println("Appetizer: anti pasti"); } public void getSoup() {} public void getSalad() {} public void getFish() {} public void getMeat() { System.out.println("Meat: chicken piccata"); } public void getPasta() {} public void getCheesePlate() {} public void getBeverage() { System.out.println("Beverage: cappuccino"); } } public void getDessert() { System.out.println("Dessert: gelato"); } public void getSorbet() {} public class AmericanMealImp implements MealImp { public void getSandwich() {} } public void getAppetizer() { System.out.println("Appetizer: nachos"); } public void getSoup() {} public class FrenchMealImp implements MealImp { public void getSalad() {} public void getAppetizer() { public void getFish() {} System.out.println("Appetizer: escargot"); } public void getSoup() {} public void getMeat() { public void getSalad() {} System.out.println("Meat: steak"); } public void getFish() {} public void getPasta() {} public void getMeat() { public void getCheesePlate() {} System.out.println("Meat: coq au vin"); } public void getBeverage() { public void getPasta() {} System.out.println("Beverage: beer"); } public void getCheesePlate() {} public void getDessert() { public void getBeverage() { System.out.println("Dessert: apple pie"); } System.out.println("Beverage: bordeaux"); } public void getSorbet() {} public void getDessert() { System.out.println("Dessert: creme brulee"); } public void getSandwich() {} public void getSorbet() {} }
桥接模式(Bridge、Implementor)(具体不同平台日志记录,抽象与实现分离)

桥接模式(Bridge、Implementor)(具体不同平台⽇志记录,抽象与实现分离)桥接模式(Bridge Pattern):将抽象部分与它的实现部分分离,使它们都可以独⽴地变化。
它是⼀种对象结构型模式,⼜称为柄体(Handle and Body)模式或接⼝(Interface)模式。
假如我们需要建⽴⼀个⽇志记录器,可以实现数据库记录和⽂本记录。
根据我们的经验我们应该将⽇志记录抽象化,在分别⽤数据库记录和⽂本记录来实现具体的功能。
后来我们需要将他分别应⽤到net平台和java平台,考虑到不同平台的记录不同我们分别将数据库记录细化为net平台上的数据库机记录和java平台上的数据库记录。
以及不同的⽂本记录。
在后来我们打算添加xml平台以及更多的平台进去。
现在发现我们的设计变得庞⼤脆弱,即便平台不同但总有相似之处,这其中的冗余代码会有很多。
假如我们不⽌沿着平台这⼀⽅向扩展呢。
因此我们需要使⽤桥接模式进⾏更加合理的设计。
桥接模式将抽象部分与他的实现部分分离,使他们都可以独⽴的变化。
抽象化:多个实体中共同的概念性联系。
如:⽇志记录实现化:抽象化的具体实现。
如:在Net平台上进⾏数据库⽇志记录。
我们可以进⾏如下设计:桥接类:抽象⽇志1public abstract class log {2private ImpLog impLog;34public log(ImpLog impLog) {5super();6this.impLog = impLog;7 }89abstract public void write(String log);1011public ImpLog getImpLog() {12return impLog;13 }1415public void setImpLog(ImpLog impLog) {16this.impLog = impLog;17 }18 }实现化⾓⾊:抽象平台1public abstract class ImpLog {23abstract public void execute(String msg);45 }具体实现化⾓⾊:java平台1public class JImpLog extends ImpLog{23 @Override4public void execute(String msg) {5 System.out.println("在java平台上," + msg);6 }78 }net平台1public class NImpLog extends ImpLog{23 @Override4public void execute(String msg) {5 System.out.println("在Net平台上,"+msg);67 }89 }桥接具体类:数据库⽇志:public class DataBaseLog extends log{public DataBaseLog(ImpLog impLog) {super(impLog);}@Overridepublic void write(String log) {getImpLog().execute("数据库⽇志:" + log);}}⽂本⽂件⽇志1public class TextFileLog extends log{23public TextFileLog(ImpLog impLog) {4super(impLog);5 }67 @Override8public void write(String log) {9 getImpLog().execute(log);10 }1112 }客户测试类:1public class BridgePattern {23public static void main(String[] args) {4 ImpLog j= new JImpLog();//建⽴java平台5 log jl = new DataBaseLog(j);//建⽴基于java 的数据库⽇志写⼊6 jl.write(" I am fine!"); //写⼊⽇志⽂件789 }1011 }。
设计模式之桥接(bridge)模式

设计模式之桥接(bridge)模式 在现实⽣活中,我们常常会⽤到两种或多种类型的笔,⽐如⽑笔和蜡笔。
假设我们需要⼤、中、⼩三种类型的画笔来绘制12中不同的颜⾊,如果我们使⽤蜡笔,需要准备3*12=36⽀。
但如果使⽤⽑笔的话,只需要提供3种型号的⽑笔,外加12个颜料盒即可,涉及的对象个数仅为3+12=15,远远⼩于36却能实现与36⽀蜡笔同样的功能。
如果需要新增⼀种画笔,并且同样需要12种颜⾊,那么蜡笔需要增加12⽀,⽽⽑笔却只需要新增1⽀。
通过分析,在蜡笔中,颜⾊和型号两个不同的变化维度耦合在⼀起,⽆论对其中任何⼀个维度进⾏扩展,都势必会影响另外⼀个维度。
但在⽑笔中,颜⾊和型号实现了分离,增加新的颜⾊或者型号都对另外⼀⽅没有任何影响。
在软件系统中,有些类型由于⾃⾝的逻辑,它具有两个或多个维度的变化。
为了解决这种多维度变化,⼜不引⼊复杂度,这就要使⽤今天介绍的Bridge桥接模式。
⼀、跨平台的图像浏览系统1.1 需求介绍M公司开发部想要开发⼀个跨平台的图像浏览系统,要求该系统能够显⽰JPG、BMP、GIF、PNG等多种格式的⽂件,并且能够在Windows、Linux以及Unix等多个操作系统上运⾏。
该系统⾸先将各种格式的⽂件解析为像素矩阵(Matrix),然后将像素矩阵显⽰在屏幕上,在不同的操作系统中可以调⽤不同的绘制函数来绘制像素矩阵。
该系统需要具备较好的扩展性以⽀持新的⽂件格式和操作系统。
1.2 初始设计 M公司开发部的程序猿针对需求,⽴马提出了⼀个初始的设计⽅案,其基本结构如下图所⽰: 通过对这个设计⽅案的分析,发现存在以下两个主要问题: (1)由于采⽤了多重继承结构,导致系统中类的个数急剧增加,系统中类的个数达到了17个。
(2)系统扩展⿇烦,由于每⼀个具体类既包括图像⽂件格式信息,⼜包含操作系统信息,因此⽆论增加新图像⽂件格式还是新的操作系统,都需要增加⼤量的具体类。
这将导致系统变得⾮常庞⼤,增加运⾏和维护开销。
水星Mercury无线路由器桥接Bridge设置图文方法

注意:做无线桥接需要路由器支持,最好是同品牌的路由器这样稳定性好一点。
今天介绍下水星Mercury无线路由器桥接Bridge设置图解,其他路由器大同小异。
首先分别登录两台路由器获取路由器LAN口的MAC地址并记录下来。
方法:登录路由
器在运行状态中的“LAN口状态”中获取。
未设置桥接前如果用无线登录时可能有冲突只能登
录一个,建议可以用有线设置,也可以给路由器分别断电用无线设置。
路由器管理界面——无线参数——基本设置勾选“开启Bridge功能”在AP1的MAC地
址中输入之前记录的对方LAN口MAC地址(两台路由器同样操作)。
在频段和模式选项中
两台路由器须一致否则无法连接。
登录副路由器(没有连接互联网的路由器)网络参数——LAN口设置在IP地址中输入
不与主路由器相同的IP地址。
副路由器:DHCP服务选择关闭,一个网络中最好只有一个DHCP服务器。
设置完成后分别重启两台路由器就可以了。
测试方法是:连接其中一台路由器后PING另一台路由器,通则表明设置成功。
tp-link中的无线桥接设置(bridge功能)

已经通过PPPOE能正常上网,目的,我样想通过功能差不多一样的B路由器把信号传递的更远。
先说A 的配置WAN口pppoe 连接猫,拨号上网,设置自动连接LAN :IP保持不变192.168.3.1无线配置:SSID:AP 无线频段设:6 (以上仅供参考,可以自己设置。
两个路由的SSID可以相同也可不同,如果相同,笔记本才可以漫游。
但无线频段必须相同),开启bridge功能,AP1中填入B的无线MAC地址,安全设置选择WEP(说明书上写的,如果桥接只支持WEP方式),两个路由器设置的加密方式和密码必须一致。
启用DHCP再说B的配置WAN口默认不变LAN:IP 192.168.3.2 (分的开点,以免冲突)无线配置:SSID:AP 无线频段设:6, 开启bridge功能,AP1中填入A的无线MAC地址(地址在路由器底部也可以看到)。
安全设置和A设置成一样的禁用DHCP,以免发生冲突。
这样是通过B的LAN口或者是无线连入(笔记本无线接入选择AP,密码就是你在安全里面设置的密码,两台都一样),都能从A获得IP地址,可以ping通A,可以共享上网。
(你想像成两个路由器的LAN口被一根网线连起来啦)网上还有一对多的桥接那么A的AP1,AP2,AP3…分别填上这些路由器的无线MAC,而这些路由器的AP1中填上A的无线MAC。
下面是TP-LINK官方的一些建议:选择设备:为了达到最好的兼容性,请选择同一品牌的无线产品配套使用。
频段设置:桥接的路由器无线频段必须相同,建议手动设置以保证频段相同。
SSID设置:无线路由器所设置的SSID可以不同,此时客户端在此网络中不能无线漫游,要想实现无线漫游需设置相同的SSID。
(这是什么意思呢,就是说如果设置成相同的SSID,你的笔记本在无线网络中只看得到一个SSID,而且你在移动时会自动切换,不用你靠谁近的时候,再在无线网络中去选择这个)。
C++设计模式-Bridge桥接模式

C++设计模式-Bridge桥接模式作⽤:将抽象部份与它的实现部份分离,使它们都可以独⽴地变化。
将抽象(Abstraction)与实现(Implementation)分离,使得⼆者可以独⽴地变化。
桥接模式号称设计模式中最难理解的模式之⼀,关键就是这个抽象和实现的分离⾮常让⼈奇怪,⼤部分⼈刚看到这个定义的时候都会认为实现就是继承⾃抽象,那怎么可能将他们分离呢。
《⼤话设计模式》中就Bridge模式的解释:⼿机品牌和软件是两个概念,不同的软件可以在不同的⼿机上,不同的⼿机可以有相同的软件,两者都具有很⼤的变动性。
如果我们单独以⼿机品牌或⼿机软件为基类来进⾏继承扩展的话,⽆疑会使类的数⽬剧增并且耦合性很⾼,(如果更改品牌或增加软件都会增加很多的变动)两种⽅式的结构如下:所以将两者抽象出来两个基类分别是PhoneBrand和PhoneSoft,那么在品牌类中聚合⼀个软件对象的基类将解决软件和⼿机扩展混乱的问题,这样两者的扩展就相对灵活,剪短了两者的必要联系,结构图如下:这样扩展品牌和软件就相对灵活独⽴,达到解耦的⽬的!UML结构图如下:抽象基类及接⼝:1、Abstraction::Operation():定义要实现的操作接⼝2、AbstractionImplement::Operation():实现抽象类Abstaction所定义操作的接⼝,由其具体派⽣类ConcreteImplemenA、ConcreteImplemenA或者其他派⽣类实现。
3、在Abstraction::Operation()中根据不同的指针多态调⽤AbstractionImplement::Operation()函数。
理解:Bridge⽤于将表⽰和实现解耦,两者可以独⽴的变化.在Abstraction类中维护⼀个AbstractionImplement类指针,需要采⽤不同的实现⽅式的时候只需要传⼊不同的AbstractionImplement派⽣类就可以了.Bridge的实现⽅式其实和Builde⼗分的相近,可以这么说:本质上是⼀样的,只是封装的东西不⼀样罢了.两者的实现都有如下的共同点:抽象出来⼀个基类,这个基类⾥⾯定义了共有的⼀些⾏为,形成接⼝函数(对接⼝编程⽽不是对实现编程),这个接⼝函数在Buildier中是BuildePart函数在Bridge中是Operation函数;其次,聚合⼀个基类的指针,如Builder模式中Director类聚合了⼀个Builder基类的指针,⽽Brige模式中Abstraction类聚合了⼀个AbstractionImplement基类的指针(优先采⽤聚合⽽不是继承);⽽在使⽤的时候,都把对这个类的使⽤封装在⼀个函数中,在Bridge中是封装在Director::Construct函数中,因为装配不同部分的过程是⼀致的,⽽在Bridge模式中则是封装在Abstraction::Operation函数中,在这个函数中调⽤对应的AbstractionImplement::Operation函数.就两个模式⽽⾔,Builder封装了不同的⽣成组成部分的⽅式,⽽Bridge封装了不同的实现⽅式.桥接模式就将实现与抽象分离开来,使得RefinedAbstraction依赖于抽象的实现,这样实现了依赖倒转原则,⽽不管左边的抽象如何变化,只要实现⽅法不变,右边的具体实现就不需要修改,⽽右边的具体实现⽅法发⽣变化,只要接⼝不变,左边的抽象也不需要修改。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
virtual void Open(); virtual void Close(); virtual void Iconify(); virtual void Deiconify();
// requests forwarded to implementation virtual void SetOrigin(const Point& at); virtual void SetExtent(const Point& extent); virtual void Raise(); virtual void模式定义 模式结构 模式的程序表示C++ 模式的程序表示Java 实例与解析 模式效果评价 模式的适用环境 模式扩展 已知应用 模式小结
Bridge-桥接:动机
考虑在一个用户界面工具箱中,一个可移植的 Window抽象部分的实现。假如采用继承机制有两个 不足之处:
桥接模式(Bridge Pattern):将抽象部分与它的 实现部分分离,使它们都可以独立地变化。它 是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。
Bridge-桥接:结构
Abstraction(Window) —定义抽象类的接口。 —维护一个指向Implementor类型对象的指针。
virtual void DrawLine(const Point&, const Point&); virtual void DrawRect(const Point&, const Point&); virtual void DrawPolygon(const Point[], int n); virtual void DrawText(const char*, const Point&);
Bridge-桥接:程序表示C++
class Window { public:
Window(View* contents);
// requests handled by window virtual void DrawContents();
class WindowImp { public:
virtual void ImpTop() = 0; virtual void ImpBottom() = 0; virtual void ImpSetExtent(const Point&) = 0; virtual void ImpSetOrigin(const Point&) = 0;
protected: WindowImp* GetWindowImp(); View* GetView();
private: WindowImp* _imp; View* _contents; // the window's contents
};
void Window::DrawRect (const Point& p1, const Point& p2) { WindowImp* imp = GetWindowImp(); imp->DeviceRect(p1.X(), p1.Y(), p2.X(), p2.Y());
(1)扩展Window抽象使之适用于不同种类的窗口或新的系统平台很不 方便。
(2)继承机制使得客户代码与平台相关。
1
Bridge-桥接:动机
Bridge模式解决以上问题的方法是,将Window抽象和它的实现部 分分别放在独立的类层次结构中。其中一个类层次结构针对窗口 接口(Window、IconWindow、TransientWindow),另外一个独 立的类层次结构针对平台相关的窗口实现部分,这个类层次结构 的根类为WindowImp。
2
Bridge-桥接:动机
2 1
Bridge-桥接:动机
对于有两个变化维度(即两个变化的原 因)的系统,采用方案二来进行设计系 统中类的个数更少,且系统扩展更为方 便。设计方案二即是桥接模式的应用。 桥接模式将继承关系转换为聚合关系, 从而降低了类与类之间的耦合,减少了 代码编写量。
Bridge-桥接:定义
virtual void DeviceRect(Coord, Coord, Coord, Coord) = 0; virtual void DeviceText(const char*, Coord, Coord) = 0; virtual void DeviceBitmap(const char*, Coord, Coord) = 0; // lots more functions for drawing on windows... protected: WindowImp(); };
• 实现化:针对抽象化给出的具体实现,就是实现化,抽象 化与实现化是一对互逆的概念,实现化产生的对象比抽象 化更具体,是对抽象化事物的进一步具体化的产物。
• 脱耦:脱耦就是将抽象化和实现化之间的耦合解脱开,或 者说是将它们之间的强关联改换成弱关联,将两个角色之 间的继承关系改为关联关系。桥接模式中的所谓脱耦,就 是指在一个软件系统的抽象化和实现化之间使用关联关系 (组合或者聚合关系)而不是继承关系,从而使两者可以 相对独立地变化,这就是桥接模式的用意。
RefinedAbstraction(IconWindow) —扩充由Abstraction定义的接口。
Bridge-桥接:结构
Implementor(WindowImp) —定义实现类的接口,该接口不一定要与Abstraction的接口完全 一致;事实上这两个接口可以完全不同。一般来讲,Implementor 接口仅提供基本操作,而Abstraction则定义了基于这些基本操作 的较高层次的操作。
ConcreteImplementor(XwindowImp,PMWindowImp) —实现Implementor接口并定义它的具体实现。
Bridge-桥接:结构
理解桥接模式,重点需要理解如何将抽象化(Abstraction)与 实现化(Implementation)脱耦,使得二者可以独立地变化。 • 抽象化:抽象化就是忽略一些信息,把不同的实体当作同 样的实体对待。在面向对象中,将对象的共同性质抽取出 来形成类的过程即为抽象化的过程。