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. 解决⽅案 --> 将⼿机的品牌和样式进⾏⽔平分割,并使⽤桥梁沟通,即使⽤桥接模式1. 桥接模式的基本介绍1. 桥接模式(Bridge模式)是指:将实现与抽象放在两个不同的类层次中,使两个层次可以独⽴改变,桥接模式是⼀种结构型设计模式2. Bridge模式基于类的最⼩设计原则,通过使⽤封装、聚合及继承等⾏为让不同的类承担不同的职责。
它的主要特点是把抽象(Abstraction)与⾏为实现(Implementation)分离开来,从⽽可以保持各部分的独⽴性以及应对他们的功能扩展桥接模式(Bridge)-原理类图1. Client:桥接模式的调⽤者2. Abstraction:抽象类,Abstraction 中维护了⼀个 Implementor 实现类的实例(聚合关系),Abstraction 充当桥接类3. RefinedAbstraction:Abstraction 的具体实现类,已经就与Implementor实现类桥接起来了4. Implementor:定义⾏为的接⼝5. ConcreteImplementor:Implementor 的具体实现类桥接模式和传统⽅式的对⽐1. 根据上⾯所述, 我们发现,在传统的⽅式中, ⼀个具体类的特性,都需要⾃⼰去通过继承体现,类的关系由继承完成,这样在类的数量上就成⼏何式增长,若品牌为三个,类型为四个,若想完整的实现所有的情况,就需要定义⼗⼆个类,2. 若使⽤上述描述中的桥接思想,我们只需将品牌和类型都以具体实现类的形式定义,再定义⼀个桥接类,分别持有品牌和类型属性. 对于不同的组合只需设置不同的属性即可2. 代码实现使⽤桥接模式改进传统⽅式,让程序具有更好的扩展性,利⽤程序维护类图:1. Brand:规定各个品牌⼿机的⾏为 ,和各个品牌的实现类//接⼝public interface Brand {void open();void close();void call();}public class XiaoMi implements Brand {@Overridepublic void open() {System.out.println(" ⼩⽶⼿机开机 ");}@Overridepublic void close() {System.out.println(" ⼩⽶⼿机关机 ");}@Overridepublic void call() {System.out.println(" ⼩⽶⼿机打电话 ");}}public class Vivo implements Brand {@Overridepublic void open() {System.out.println(" Vivo⼿机开机 ");}@Overridepublic void close() {System.out.println(" Vivo⼿机关机 ");}@Overridepublic void call() {System.out.println(" Vivo⼿机打电话 ");}}2. Phone:电话的抽象类,在该类中聚合了⼀个 Brand 接⼝的具体实现类 ,充当桥接的作⽤public abstract class Phone {// 组合品牌private Brand brand;// 构造器public Phone(Brand brand) {this.brand = brand;}protected void open() {this.brand.open();}protected void close() {this.brand.close();}protected void call() {this.brand.call();}}3. 继承抽象⽗类 Phone的各个款式的⼿机, 对抽象⽗类中的⽅法进⾏重写//折叠式⼿机类,继承抽象类 Phonepublic class FoldedPhone extends Phone {// 构造器public FoldedPhone(Brand brand) {super(brand);}@Overridepublic void open() {super.open();System.out.println(" 折叠样式⼿机 ");}@Overridepublic void close() {super.close();System.out.println(" 折叠样式⼿机 ");}@Overridepublic void call() {super.call();System.out.println(" 折叠样式⼿机 ");}}public class UpRightPhone extends Phone {// 构造器public UpRightPhone(Brand brand) {super(brand);}@Overridepublic void open() {super.open();System.out.println(" 直⽴样式⼿机 ");}@Overridepublic void close() {super.close();System.out.println(" 直⽴样式⼿机 ");}@Overridepublic void call() {super.call();System.out.println(" 直⽴样式⼿机 ");}}4. 客户端,可以看到,使⽤桥接模式可以轻松地组合出不同⼿机类型、不同品牌的⼿机public class Client {public static void main(String[] args) {// 折叠式的⼩⽶⼿机 (样式 + 品牌 )Phone phone1 = new FoldedPhone(new XiaoMi());phone1.open();phone1.call();phone1.close();System.out.println("=======================");// 折叠式的Vivo⼿机 (样式 + 品牌 )Phone phone2 = new FoldedPhone(new Vivo());phone2.open();phone2.call();phone2.close();System.out.println("==============");// 直⽴式的⼩⽶⼿机 (样式 + 品牌 )UpRightPhone phone3 = new UpRightPhone(new XiaoMi());phone3.open();phone3.call();phone3.close();System.out.println("==============");// 直⽴式的Vivo⼿机 (样式 + 品牌 )UpRightPhone phone4 = new UpRightPhone(new Vivo());phone4.open();phone4.call();phone4.close();}}总结:1. 可以看出,我们将品牌做成各个具体的实现类,使⽤Phone 作为桥梁,可以持有不同的品牌2. 因为此案例中只有两个属性,所以我们将款式的表⽰,体现为继承的⽅式 ,不同的款式,建⽴不同的类,继承抽象桥梁类Phone,也就可以持有不同的品牌了3. 若此时我们加了⼀个品牌或者加了⼀个款式,只需加⼀个类即可3. JDBC 源码分析Jdbc 的 Driver接⼝,如果从桥接模式来看, Driver就是⼀个接⼝(⾏为规范),下⾯可以有MySQL的Driver, Oracle的Driver,这些就可以当做实现接⼝类类图:1. 对于java定义的Connection 接⼝,不同的数据库有其相应的实现,Mysql Oracle 等2. 客户端通过桥接对象 DriverManager 去聚合各个数据源的实现类, 可以通过⽅法getConnection 获取@CallerSensitivepublic static Connection getConnection(String url,java.util.Properties info) throws SQLException {return (getConnection(url, info, Reflection.getCallerClass()));}4. 桥接模式的注意事项和细节1. 实现了抽象和实现部分的分离,从⽽极⼤的提供了系统的灵活性,让抽象部分和实现部分独⽴开来,这有助于系统进⾏分层设计,从⽽产⽣更好的结构化系统。
设计模式之桥接模式PPT课件
MapControl
+ShowRainData() +ShowSeedData() +ShowLandLayoutData() +……()
?
三. 桥接模式
场景4:
在程序中以地图形式展示年 降雨、农作物播种、农作物 收获、土地利用、土地规 划……数据,并提供输出为 分省柱状图的功能。
三. 桥接模式
阿尔托希望将它们融洽地联系在一起设计模式的定义设计模式是被命名的有组织的信息它捕获了在一定场景中包含相关作用力的问题的解决方案的本质结构和内在含义这种解决方案被证明是成功艺术家和其他人一样专注于自己的工作以至于不能在工作和休息之间有个明确的界线
设计模式 之
桥接模式
2011.06
主要内容:
一. 再论“面向对象” 二. 设计模式的特性 三. 桥接模式
三. 桥接模式
场景5的解决方案:
主窗体/主页面类
数据接口/抽象类 +Operation()
-imp.OperationImp()
1
*
<<interface>> 数据展示接口
+OperationImp()
年降雨数据
农作物播种数据
……
地图显示
生成柱状图
生成报表 ……
三. 桥接模式
场景5的解决方案:
报表抽象类
MapControl
+ShowRainData() +ShowSeedData() +ShowLandLayoutData() +……()
三. 桥接模式
场景5:
在程序中以地图形式展示年降 雨、农作物播种、农作物收获、 土地利用、土地规划……数据, 并提供输出为分省柱状图的功 能。提供输出报表的功能,根 据不同业务的需要,报表的格 式可能有几十种……
设计模式(08):结构型模式(二)桥接模式(Bridge)
设计模式(08):结构型模式(⼆)桥接模式(Bridge)⼀、动机(Motivation)在很多游戏场景中,会有这样的情况:【装备】本⾝会有的⾃⼰固有的逻辑,⽐如枪⽀,会有型号的问题,同时现在很多的游戏⼜在不同的介质平台上运⾏和使⽤,这样就使得游戏的【装备】具有了两个变化的维度——⼀个变化的维度为“平台的变化”,另⼀个变化的维度为“型号的变化”。
如果我们要写代码实现这款游戏,难道我们针对每种平台都实现⼀套独⽴的【装备】吗?复⽤在哪⾥?如何应对这种“多维度的变化”?如何利⽤⾯向对象技术来使得【装备】可以轻松地沿着“平台”和“型号”两个⽅向变化,⽽不引⼊额外的复杂度?⼆、意图(Intent)将抽象部分与实现部分分离,使它们都可以独⽴地变化。
桥模式不能只是认为是抽象和实现的分离,它其实并不仅限于此。
其实两个都是抽象的部分,更确切的理解,应该是将⼀个事物中多个维度的变化分离。
三、结构(Structure)其中imp的地⽅就是⼀个组合。
Abstraction就是我们例⼦中的Tank,它的⼦类RefinedAbstraction就是T50等型号。
Implementor是TankPlatformImplementation类,ConcreteImplementorA和ConcreteImplementorB分别是PCTankImplementation和MobileTankImplementation。
整个设计模式的关键就是组合的使⽤。
四、模式的组成桥接模式的结构包括Abstraction、RefinedAbstraction、Implementor、ConcreteImplementorA和ConcreteImplementorB五个部分,其中:(1)、抽象化⾓⾊(Abstraction):抽象化给出的定义,并保存⼀个对实现化对象(Implementor)的引⽤。
(2)、修正抽象化⾓⾊(Refined Abstraction):扩展抽象化⾓⾊,改变和修正⽗类对抽象化的定义。
桥接(Bridge)模式【实验】
6.3.1 桥接模式的由来---案例2
A
XD1() XD2()
B
A
YD1() YD2()
B
X操作系统 XD1和XD2是X操作系统提供的接口
Y操作系统
返回目录
6.3.1 桥接模式的由来---案例2
A F(){ xd1(); xd2(); }
XD1() XD2()
A F(){ yd1(); yd2(); }
y操作系统
D1(){ xd1(); } D1(){ yd1(); }
用桥接模式解决前述问题
返回目录
6.3.1 桥接模式的由来---案例3
问题说明
返回目录
6.3.2 桥接模式的意图和适用性
传统地,当一个抽象可能有多个实现时,通常用 继承来协调它们。 抽象类定义该抽象的接口,而具体的子类则用不 同的方式加以实现。但是此方法有时不够灵活。 继承机制将抽象部分与它的实现部分固定在一起, 使得难以对抽象部分和实现部分独立地进行修改。 扩充和重用。 桥接模式的作用就是将抽象部分与实际部分分离, 使它可以独立的变化。
SuperSizeMilkcoffee
SuperSizeoriginalcoffee
pourCoffee
pourCoffee
Pouroneservingmilk(); for (int i = 0; i < 2; i++) { pouroneservingCoffee(); }
返回目录
6.3.1 桥接模式的由来---案例1
思考:加入咖啡可以添加橙汁、苹果汁,怎么办? 增加小杯怎么办?
返回目录
6.3.1 桥接模式的由来---案例1
coffee
6桥接
桥接模式:
【二幕】 :讲台(祥爷办公室)
人物简介:呼和浩特XXX公司的高级程序员。
安璐的解决方案(继承):
安璐解决方案的缺点:
很多情况用继承会带来麻烦,比如,对象的继承关系是在编 译时就定义好了,所以无法在运行时改变从父类继承的实现。 子类的实现与它的父类有非常紧密的依赖关系,以至于父类 实现中的任何变化必然会导致子类发生变化。当你需要复用 子类时,如果继承下来的实现不适合解决新的问题,则父类 必须重写或被其他适合的类替换。这种依赖关系限制了灵活 性并最终限制了复用性。在面向对象设计中有合成/聚合复 用原则,即优先使用对象合成/聚合,而不是类继承。(合 成是一种强的拥有关系,体现严格的部分与整体;聚合是一 种弱的拥有关系,体现的是A对象可以包含B对象,但B对象 不是A对象的一部分)
拿刚才的例子来讲
Bridge Pattern
意图:
将抽象部分与实现部分分离,使他们都可以独立地 变化。
别名:Handle/Body
结构:结构图
结构:参与者
桥接模式包含如下角色: • • •
Abstraction:抽象类 RefinedAbstraction:扩充抽象类 Implementor:实现类接口
•
•
桥接模式:
桥接模式的缺点
•
桥接模式的引入会增加系统的理解与设计难度,由于 聚合关联关系建立在抽象层,要求开发者针对抽象进 行设计与编程。
•
桥接模式要求正确识别出系统中两个独立变化的维度, 因此其使用范围具有一定的局限性。
桥接模式:
模式适用环境
在以下情况下可以使用桥接模式:
•
桥接模式案例
Bridge-AP模式和Bridge-Sriation模式互通
1.设备供电与本地连接相通
2.修改ip地址与设备相同网段
3.
4.通过游览器访问设备IP地址进行配置管理
5.
6.配置设备工作模式(主网桥配置成ap模式)
7.
8.选择无线(虚拟ap)配置设备SSID勾选WDS(wuxian为ssid)
9.
10.选择无线(射频)里面修改频宽,信道,应用变更
11.
12.保存设备修改信息换第二个无线设备做Bridge-Sriation模式
13.
14.选择接口(局域网)修改设备IP(于第一台设备相同网段)
15.
16.选择无线(射频)确定与第一台设备一致
17.
18.扫描中心基站ssid—无线---虚拟ap(显示配置信息)---点击修改
19.
20.选择扫描
21.
22.选择第一个设备ssid
23.
24.勾选锁定到ap 选择应用变更
25.
26.连接互相ping一下确定连接成功
27.
28.
到此桥接模式配置成功。
桥接模式
4
Your text here
•抽象化 存在于多个实体中的共同的概念性联系,就是抽象化。作为一个过程, 抽象化就是忽略一些信息,从而把不同的实体当做同样的实体对待。 •实现化 抽象化给出的具体实现,就是实现化。 •脱耦 所谓耦合,就是两个实体的行为的某种强关联。而将它们的强关联去掉, 就是耦合的解脱,或称脱耦。在这里,脱耦是指将抽象化和实现化之间的耦 合解脱开,或者说是将它们之间的强关联改换成弱关联。 将两个角色之间的继承关系改为聚合关系,就是将它们之间的强关联改换 成为弱关联。因此,桥梁模式中的所谓脱耦,就是指在一个软件系统的抽象 化和实现化之间使用组合/聚合关系而不是继承关系,从而使两者可以相对独 立地变化。这就是桥梁模式的用意。
Date text here
四 桥接模式的三个关键词
5
五
• 讲解
示意性源代码
Date
Your text here
6
Thank you!
桥接模式
一 认识桥接模式
• Bridge模式又叫做桥接模式,是构造型设计模 式之一。Bridge模式基于类的最小设计原则, 通过使用封装,聚合以及继承等行为让不同的 类承担不同的责任。它的主要特点是把抽象和 行为实现(abstraction)分离开来,从而可以保 持各部分的独立性以及应对它们的功能扩展。
Date
2
二
桥接模式的结构
Date
Your text here
3
三
1 client
桥接模式的角色和职责
#
Bridge模式的使用者 2 Abstraction 抽象类接口(接口或抽象类) 维护对行为实现(lmplementor)的引用 3 Refined Abstraction Abstraction 的子类 4 lmplementor 行为实现类接口(Abstraction接口定义了基于lmplementor的更高 层次的操作) 5 Concretelmplementor lmplementor子类
【全版】桥接模式图文推荐PPT
。Hale Waihona Puke + bepaint (String penType, String name) : void
理解桥接模式,重点需要理解如何将抽象化(Abstraction)、实现化(Implementation)和脱耦,.使.. 得二者可以独立地变化。
operationImpl();
Green
(2) 桥接模式有时类似于多继承方案,但是多继承方案违背了类的单一职责原则(即一个类只有一个变化的原因),复用性比较差,
(1) 第一种设计方案是p为u每b一lic种v形o状id都o提p供er一at套io各n种Im颜p色l(的);版本。 脱关耦联: 关脱系耦。就是将}抽象化和实现化之间的耦合解脱开,或者说是将它们之间的强关联改换成弱关联,将两个角色之间的继承关系改为
Implementor:实现类接口,定义基本的方法,具体实现交给子类完成。 (1) Java语言通过Java虚拟机实现了平台的无关性。 (2) 桥接模式有时类似于多继承方案,但是多继承方案违背了类的单一职责原则(即一个类只有一个变化的原因),复用性比较差, 而且多继承结构中类的个数非常庞大,桥接模式是比多继承方案更好的解决方法。
ConcreteImplementorB
+ operationImpl () ...
桥接模式核心代码
public void operation() Implementor:实现类接口,定义基本的方法,具体实现交给子类完成。 对于有两个变化维度(即两个变化的原因)的系统,采用方案二来进行设计系统中类的个数更少,且系统扩展更为方便。
桥接模式的动机
(2) 第二种设计方案是根据实际需要对形状和颜色进 行组合
桥接模式动机
对于有两个变化维度(即两个变化的原因)的系统,采 用方案二来进行设计系统中类的个数更少,且系统扩展更 为方便。设计方案二即是桥接模式的应用。桥接模式将继 承关系转换为关联关系,从而降低了类与类之间的耦合, 减少了代码编写量。
- 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)脱耦,使得二者可以独立地变化。 • 抽象化:抽象化就是忽略一些信息,把不同的实体当作同 样的实体对待。在面向对象中,将对象的共同性质抽取出 来形成类的过程即为抽象化的过程。