桥接模式又称为柄体模式或接口模式。桥接模式的用意就是"将抽象化与实现化解耦,使得二者可以独立变化"。

抽象化:

  存在于多个实体中的共同的概念性联系,就是抽象化。作为一个过程,抽象化就是忽略一些信息,从而把不同实体当做同样的实体对待。

实现化:

  抽象化给出的具体实现,就是实现化。

脱耦:

  耦合是指两个实体的行为的某种强关联。将它们的强关联去掉,就是耦合的解脱或称脱耦。在这里脱耦是将抽象化和实现化的耦合解脱开,或者说是将它们的强关联变为弱关联。继承是强关联。

  强关联是指编译时期已经确定的,无法在运行时期动态改变的关联;所谓弱关联就是可以动态地确定并在运行时动态地改变的关联。聚合是弱关联。

  将两个角色的继承关系改为聚合关系,就是将它们之间强关联变为弱关联。因此,桥梁模式的脱耦,就是指在一个软件系统的抽象化和实现化之间使用组合/聚合关系而不是继承关系,从而使两者可以独立地变化。

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)模式的更多相关文章

  1. 设计模式初探-桥接(Bridge)模式

    桥接(Bridge)模式,又称Handle/Body模式,属于对象结构型模式.用于将抽象部分与它的实现部分分离,使它们都可以独立地变化.比如常见的电脑窗口界面,不同的操作系统其窗口界面绘制的原理肯定不 ...

  2. Java 实现桥接(Bridge)模式

    类图: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamp3d21scDQ1Ng==/font/5a6L5L2T/fontsize/400/fill/I0 ...

  3. 设计模式C++描述----09.桥接(Bridge)模式

    一. 举例 N年前: 计算机最先出来时,软件和硬件是一绑在一起的,比如IBM出了一台电脑,上面有一个定制的系统,假如叫 IBM_Win,这个IBM_Win系统当然不能在HP电脑上运行,同样HP出的HP ...

  4. Java设计模式---桥接Bridge模式

    参考于 : 大话设计模式 马士兵设计模式视频 写在开头: 桥接模式主要用于一件事物分成了两个维度,进行排列组合,比如礼物,可以分成优雅的礼物(抽象),花(具体),排列组合优雅的花! 1.为什么使用桥接 ...

  5. 设计模式--桥接(Bridge)模式

    1.概述: 桥接模式:把抽象和行为分离开来,中间需要某个介质来连接抽象化和行为化.此模式的概述听起来非常像适配器模式,不要搞混了,虽然都是借用中间介质,但意义不同.最典型的桥接模式就是:JDBC.通过 ...

  6. 漫谈设计模式(三):桥接(Bridge)模式 —— 将类功能、结构两层次分离

    1.前言 类主要有两个层次,一个是功能层次,另一个是实现层次. 功能层次,一般应用于当前类不能满足多样化的业务需求,让子类去继承(具体)父类,添加加一些父类中没有的功能(一般是增加新的方法),这就属于 ...

  7. 【设计模式】Bridge模式(桥接模式)

    最近的一次面试中,被问到桥接模式,以前呢并没有很仔细的研究过这个设计模式,借此机会剖析一下. 先给出自己对这个模式理解后的源码: interface A{ void methodA(); } inte ...

  8. Bridge(桥接)模式

    1. 概述 在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度 ...

  9. 接口型模式(二)Bridge(桥接)模式

    目的: 将抽象与抽象方法的实现相分离,使得它们可以独自变化.常用于驱动程序中,使得顶层逻辑不受驱动底层改变的影响,如数据库的变化. 关键词:Bridge, 抽象与实现分离,驱动程序 必要性:从一般抽象 ...

随机推荐

  1. Centos下安装LoadRunner负载机

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAd0AAADfCAIAAAA84J6GAAAgAElEQVR4nJzb93cbR6In+uK/8v6Fd8

  2. ASP.NET Core使用EPPlus导入导出Excel

    开发过程中,经常会遇到导入导出数据的需求,本篇博客介绍在.NET Core中如何使用EPPlus组件导入导出Excel EPPlus: EPPlus是使用Open Office XML格式(xlsx) ...

  3. canvas与svg整理与区别

    1.canvas画布(位图) 2.绘制矢量图 1.不要在style中给canvas设置宽高 会有位移差 2. //获取元素 var c=document.getElementById("c& ...

  4. idea使用过程中的一些常见问题,做个笔记

    :当实现这个接口方法时重载是不允许的. 首先我相信我的代码肯定没问题,因为我实现的接口确实有这个方法.在编程阶段就提示这个错误,于是我有理由相信应该是编译错误!通过google,解决办法so easy ...

  5. CDA数据分析【数据收集】

    一.机器收集数据 机器收集数据会从不同角度对数据进行抓取和采集,与之前手动收集数据不同,机器收集数据不再是用小样本.特定样本来采集和分析整体数据,而是采用大样本或整体数据进行分析,这打破了原来的数据分 ...

  6. elastic date时区问题解决办法

    之前介绍filter date插件时就谈到时区问题,但是没有说明白.最近在使用range查询时间范围内的数据时出现了数据量不一致的情况.特地了解了下ELK Stack中关于时区的问题. 问题: 使用k ...

  7. Linux shell for循环结构

    Linux Shell   for循环结构 循环结构            1:循环开始条件      2:循环操作      3:循环终止的条件 shell语言          for,while ...

  8. Open Physics

    1.开放物理计划. 开放物理计划,英文Open Physics.是AMD公司为自己的3A平台打造的物理模拟计算平台,以OpenCL为基础,由CPU+GPU联合计算完成.所谓“开放”,是指参与这个计划的 ...

  9. 【servlet】Servlet快速入门&使用Eclipse发布web项目

    创建时间:6.15 1.什么是Servlet Servlet 运行在服务端的Java小程序,是sun公司提供一套规范(接口),用来处理客户端请求.响应给浏览器的动态资源.但servlet的实质就是ja ...

  10. window开机启动

    C:\Users\sunyues\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup 再次文件夹下写脚本就可 @echo off ...