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

抽象化:

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

实现化:

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

脱耦:

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

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

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

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. Vue递归组件实现层层嵌套显示数据

    问题来自朋友...记录一下 需求是表格头部后端返回的数据中是不确定的 n维数据,表头存在于 listVo 字段中,如何实现层层显示呢? 温馨提示,以下内容为5张大图,请打开 WIFI 享用... 以下 ...

  2. 实验吧简单的sql注入3

    今天早上起来发现有人评论说我没更新实验吧sql注入3,主要是因为前段时间都去做bugku去了 但是重做这道题发现以前的姿势不行了,exp()报错不再溢出,现在不能用这个姿势,所以这里重新整理了一遍思路 ...

  3. 《Android开发艺术探索》读书笔记之IntentFillter的匹配规则

    使用intent启动不同组件的方法 组件类型 启动方法 Activity startActivity(Intent intent) startActivityForResult(Intent inte ...

  4. WDA基础十八:Select option配置

    为了省代码...为了方便管理WDA的查询条件... 首先建配置表: 说明: 上面的KEY基本都是维护的维度,可以根据销售组织,根据用户组,根据组件,根据SELECT OPTION的不同...等等,可以 ...

  5. 一个很简单的SpringCloud项目,集成Feign、Hystrix

    Feign的功能:这是个消费者,根据服务注册在Eureka的ID去找到该服务,并调用接口Hystrix的功能:熔断器,假如A服务需要调用B服务的/cities接口获取数据,那就在A服务的control ...

  6. elasticsearch查询篇索引映射文档数据准备

    elasticsearch查询篇索引映射文档数据准备 我们后面要讲elasticsearch查询,先来准备下索引,映射以及文档: 我们先用Head插件建立索引film,然后建立映射 POST http ...

  7. mysql官网下载对应的mysql包

    1.  在百度搜索mysql,点击mysql官网上下载mysql的地址 在url直接输入mysql的下载地址也可以:https://dev.mysql.com/downloads/mysql/ 如图: ...

  8. django framework插件使用1

    安装 REST框架要求以下内容: Python(3.5.3.6.3.7) Django(1.11.2.0.2.1.2.2) pip install djangorestframework pip in ...

  9. 可变lambda, lambda使用mutable关键字

    关于lambda的捕获和调用 C++ primer上对可变lambda举的例子如下: size_t v1=42; auto f=[v1] () mutable{return ++v1; }; v1=0 ...

  10. yoast breadcrumb面包屑导航修改去掉product

    前面我们创建了wordpress添加post_type自定义文章类型和调用自定义post_type文章,现在yoast 面包屑导航出现home >product >分类1,想要把produ ...