桥接(Bridge)模式
桥接模式又称为柄体模式或接口模式。桥接模式的用意就是"将抽象化与实现化解耦,使得二者可以独立变化"。
抽象化:
存在于多个实体中的共同的概念性联系,就是抽象化。作为一个过程,抽象化就是忽略一些信息,从而把不同实体当做同样的实体对待。
实现化:
抽象化给出的具体实现,就是实现化。
脱耦:
耦合是指两个实体的行为的某种强关联。将它们的强关联去掉,就是耦合的解脱或称脱耦。在这里脱耦是将抽象化和实现化的耦合解脱开,或者说是将它们的强关联变为弱关联。继承是强关联。
强关联是指编译时期已经确定的,无法在运行时期动态改变的关联;所谓弱关联就是可以动态地确定并在运行时动态地改变的关联。聚合是弱关联。
将两个角色的继承关系改为聚合关系,就是将它们之间强关联变为弱关联。因此,桥梁模式的脱耦,就是指在一个软件系统的抽象化和实现化之间使用组合/聚合关系而不是继承关系,从而使两者可以独立地变化。
1. 类图与角色
这个系统有两个等级结构:
由抽象化角色和修正抽象化角色组成的抽象化等级结构;
由实现化角色和两个具体实现化角色所组成的实现化等级结构。
涉及的角色有:
抽象化(Abstraction)角色:抽象化给出的定义,并保存一个对实现化对象的引用。
修正抽象化(Refined Abstraction)角色:扩展抽象化角色,改变和修正父类对抽象化的定义。
实现化(implementor)角色:这个角色给出实现化角色的接口,但不给出具体的实现。这个接口不一定和抽象化角色定义相同的接口、实现化角色应当只给出低层操作,而抽象化角色应当只给出基于低层操作的更高一层的操作。
具体实现化角色:这个角色给出实现化角色接口的具体实现。
代码如下:
package cn.qlq.bridge; public abstract class Implementor { public abstract void operationImpl();
}
package cn.qlq.bridge; public class ConcreteImplementorA extends Implementor { @Override
public void operationImpl() {
System.out.println(" ConcreteImplementorA operationImpl ");
} }
package cn.qlq.bridge; public class ConcreteImplementorB extends Implementor { @Override
public void operationImpl() {
System.out.println(" ConcreteImplementorB operationImpl ");
} }
package cn.qlq.bridge; public class Abstraction { private Implementor implementor; public void operation() {
if (implementor != null) {
implementor.operationImpl();
}
} public Implementor getImplementor() {
return implementor;
} public void setImplementor(Implementor implementor) {
this.implementor = implementor;
} }
package cn.qlq.bridge; public class RefinedAbstraction extends Abstraction { @Override
public void operation() {
// 增强逻辑
} }
2. 桥接模式的例子
一个例子: 手机有多种品牌,又有不同的软件。
(1)不采用桥接模式:
如果需要增加一个MP3音乐播放器。做法就是在手机品牌M和手机品牌N下面都增加一个子类,但是这两个子类的差别可能并不大。
如果需要增加一个品牌L更加复杂,需要增加一个类手机品牌L继承手机品牌,并且还需要两个子类手机品牌L通讯录和手机品牌L游戏并继承手机品牌L。
(2)采用桥接模式的设计如下:
一个抽象"手机品牌"和抽象类"手机软件",不同的品牌和不同的软件分别继承于他们。手机品牌包含有手机软件,但是手机软件并不是品牌的一部分,所以他们之间是聚合关系。
代码如下:
package cn.qlq.bridge.example.plain; import java.util.List; /**
* 抽象手机品牌
*
* @author Administrator
*
*/
public abstract class HandsetBrand { protected List<HandsetSoft> handsetSofts; public HandsetBrand(List<HandsetSoft> handsetSofts) {
super();
this.handsetSofts = handsetSofts;
} abstract void run(); }
package cn.qlq.bridge.example.plain; import java.util.List; /**
* 手机品牌M
*
* @author Administrator
*
*/
public class HandsetBrandM extends HandsetBrand { public HandsetBrandM(List<HandsetSoft> handsetSofts) {
super(handsetSofts);
} @Override
void run() {
for (HandsetSoft handsetSoft : handsetSofts) {
handsetSoft.run();
}
} }
package cn.qlq.bridge.example.plain; import java.util.List; /**
* 手机品牌N
*
* @author Administrator
*
*/
public class HandsetBrandN extends HandsetBrand { public HandsetBrandN(List<HandsetSoft> handsetSofts) {
super(handsetSofts);
} @Override
void run() {
for (HandsetSoft handsetSoft : handsetSofts) {
handsetSoft.run();
}
} }
package cn.qlq.bridge.example.plain; /**
* 手机软件
*
* @author Administrator
*
*/
public abstract class HandsetSoft { abstract void run();
}
package cn.qlq.bridge.example.plain; /**
* 手机游戏
*
* @author Administrator
*
*/
public class HandsetGame extends HandsetSoft { @Override
void run() {
System.out.println("手机游戏");
} }
package cn.qlq.bridge.example.plain; public class HandsetAddressList extends HandsetSoft { @Override
void run() {
System.out.println("手机通讯录");
} }
这时候如果增加一个功能,只需要增加一个类:
package cn.qlq.bridge.example.plain; public class HandsetMP3 extends HandsetSoft { @Override
void run() {
System.out.println("mp3");
} }
如果需要增加一个新品牌L,也是增加一个类:
package cn.qlq.bridge.example.plain; import java.util.List; /**
* 手机品牌L
*
* @author Administrator
*
*/
public class HandsetBrandL extends HandsetBrand { public HandsetBrandL(List<HandsetSoft> handsetSofts) {
super(handsetSofts);
} @Override
void run() {
for (HandsetSoft handsetSoft : handsetSofts) {
handsetSoft.run();
}
} }
3. 桥接模式适用场景
如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的联系。
设计要求实现化角色的任何改变不影响客户端,或者实现化角色的改变对客户端是完全透明的。
一个构件有多于一个的抽象化角色和实现化角色,系统需要它们之间进行动态解耦。
虽然在系统中使用继承是没有问题的,但是由于抽象化角色和具体化角色需要独立变化,设计要求需要独立管理这两者。
总结:
上面的设计也符合开闭原则。相比聚合,继承更容易造成不必要的麻烦。在使用继承时,一定要在"is - a" 关系的时候再考虑使用。
由于上面的两个抽象类之间有一个聚合的关系箭头,有一条聚合线,这么理解更容易记住 桥接 模式。
桥接(Bridge)模式的更多相关文章
- 设计模式初探-桥接(Bridge)模式
桥接(Bridge)模式,又称Handle/Body模式,属于对象结构型模式.用于将抽象部分与它的实现部分分离,使它们都可以独立地变化.比如常见的电脑窗口界面,不同的操作系统其窗口界面绘制的原理肯定不 ...
- Java 实现桥接(Bridge)模式
类图: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamp3d21scDQ1Ng==/font/5a6L5L2T/fontsize/400/fill/I0 ...
- 设计模式C++描述----09.桥接(Bridge)模式
一. 举例 N年前: 计算机最先出来时,软件和硬件是一绑在一起的,比如IBM出了一台电脑,上面有一个定制的系统,假如叫 IBM_Win,这个IBM_Win系统当然不能在HP电脑上运行,同样HP出的HP ...
- Java设计模式---桥接Bridge模式
参考于 : 大话设计模式 马士兵设计模式视频 写在开头: 桥接模式主要用于一件事物分成了两个维度,进行排列组合,比如礼物,可以分成优雅的礼物(抽象),花(具体),排列组合优雅的花! 1.为什么使用桥接 ...
- 设计模式--桥接(Bridge)模式
1.概述: 桥接模式:把抽象和行为分离开来,中间需要某个介质来连接抽象化和行为化.此模式的概述听起来非常像适配器模式,不要搞混了,虽然都是借用中间介质,但意义不同.最典型的桥接模式就是:JDBC.通过 ...
- 漫谈设计模式(三):桥接(Bridge)模式 —— 将类功能、结构两层次分离
1.前言 类主要有两个层次,一个是功能层次,另一个是实现层次. 功能层次,一般应用于当前类不能满足多样化的业务需求,让子类去继承(具体)父类,添加加一些父类中没有的功能(一般是增加新的方法),这就属于 ...
- 【设计模式】Bridge模式(桥接模式)
最近的一次面试中,被问到桥接模式,以前呢并没有很仔细的研究过这个设计模式,借此机会剖析一下. 先给出自己对这个模式理解后的源码: interface A{ void methodA(); } inte ...
- Bridge(桥接)模式
1. 概述 在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度 ...
- 接口型模式(二)Bridge(桥接)模式
目的: 将抽象与抽象方法的实现相分离,使得它们可以独自变化.常用于驱动程序中,使得顶层逻辑不受驱动底层改变的影响,如数据库的变化. 关键词:Bridge, 抽象与实现分离,驱动程序 必要性:从一般抽象 ...
随机推荐
- C# abstract class Interface的介绍
1.基本概念介绍 抽象类: 1.抽象方法只作声明,而不包含实现,可以看成是没有实现体的虚方法 2.抽象类可以但不是必须有抽象属性和抽象方法,但是一旦有了抽象方法,就一定要把这个类声明为抽象类 3.具体 ...
- springmvc之静态资源访问不到 -记一次惨痛的经历
springmvc之静态资源访问不到 -记一次惨痛的经历 问题描述:项目正常启动,可以访问页面,但是无法找到静态资源文件,如css,js等文件资源. 控制台: $ 未定义 页面: GET http:/ ...
- Nginx实现防盗链的方式
一.ngx_http_referer_module(阻挡来源非法的域名请求),配置如下: location ~.*\. (gif|jpg|png|flv|swf|rar|zip)$ { valid_r ...
- 递归删除文件和文件夹(bat)
递归删除当前目录下指定的文件和文件夹,使用了通配符,Win10下亲测有效,仅供参考! Batch Code 123456 @echo off echo del file... for /r % ...
- 01篇ELK日志系统——升级版集群之elasticsearch集群的搭建
[ 前言:以前搭了个简单的ELK日志系统,以我个人的感觉来说,ELK日志系统还是非常好用的.以前没有弄这个ELK日志系统的时候,线上的项目出了bug,报错了,要定位错误是什么,错误出现在哪个java代 ...
- 使用gacutil把COM组件注册到全局缓存GAC中
我们在编写软件的时候,有时候需要调用COM组件,那就需要注册了,注册有两种,一种是使用regasm 在程序运行的时候注册,参考“pb调用C#编写的DLL类库“,不过受路径的限制.还有一种注册方式,使用 ...
- 一个从tensorflow_1.14.0-gpu-py3-jupyter镜像生成公司实际需求的Dockerfile
外部的标准镜像,肯定满足不了公司的实际要求咯~~ 所以,根据同事的需求,重新制作了这个包. 其中可用库为tensorflow,numpy, pandas,scikit-learn,jieba,gens ...
- vue之ajax
[前言] Vue里发送AJAX有很多工具可以供开发者使用 ①浏览器自带的fetch函数 ②vue之前推荐的vue-resource第三方模块 ③vue官方目前强力推荐的axios第三方模块 axios ...
- JAVA类与类之间的关系及代码示例
参考链接:https://blog.csdn.net/wq6ylg08/article/details/81092056
- 用 tomcat 部署 Jenkins
在tomcat 下面部署 Jenkins 版本 tomcat (7.0.94) + jdk (7) + jenkins (2.46.3) 前两次没有部署成功,应该是 jdk 版本的问题, 如果不成功 ...