一、引言

今天我们要讲【结构型】设计模式的第二个模式,该模式是【桥接模式】,也有叫【桥模式】的,英文名称:Bridge Pattern。大家第一次看到这个名称会想到什么呢?我第一次看到这个模式根据名称猜肯定是连接什么东西的。因为桥在我们现实生活中经常是连接着A地和B地,再往后来发展,桥引申为一种纽带,比如:丝绸之路是连接亚洲和欧洲的桥梁。有了桥,我们出行方便了,从一个地方到另一个地方在有桥的情况更方便了(此处不许抬杠,当然是需要桥的情况)。桥是针对桥的使用环境来说的,解决了跨越和衔接的问题。在设计模式中的【桥模式】也有类似的概念,是连接了两个不同维度的东西,而且这两个维度又有强烈的变化,什么叫强烈呢,经常变化,什么是经常呢?哈哈,自己理解吧。

二、桥接模式的详细介绍

2.1、动机(Motivate)

在很多游戏场景中,会有这样的情况:【装备】本身会有的自己固有的逻辑,比如枪支,会有型号的问题,同时现在很多的游戏又在不同的介质平台上运行和使用,这样就使得游戏的【装备】具有了两个变化的维度——一个变化的维度为“平台的变化”,另一个变化的维度为“型号的变化”。如果我们要写代码实现这款游戏,难道我们针对每种平台都实现一套独立的【装备】吗?复用在哪里?如何应对这种“多维度的变化”?如何利用面向对象技术来使得【装备】可以轻松地沿着“平台”和“型号”两个方向变化,而不引入额外的复杂度?

2.2、意图(Intent)

将抽象部分与实现部分分离,使它们都可以独立地变化。                                                                  --《设计模式》Gof

桥模式不能只是认为是抽象和实现的分离,它其实并不仅限于此。其实两个都是抽象的部分,更确切的理解,应该是将一个事物中多个维度的变化分离。

2.3、结构图(Structure)

2.4、模式的组成

桥接模式的结构包括Abstraction、RefinedAbstraction、Implementor、ConcreteImplementorA和ConcreteImplementorB五个部分,其中:

(1)、抽象化角色(Abstraction):抽象化给出的定义,并保存一个对实现化对象(Implementor)的引用。

(2)、修正抽象化角色(Refined Abstraction):扩展抽象化角色,改变和修正父类对抽象化的定义。

(3)、实现化角色(Implementor):这个角色给出实现化角色的接口,但不给出具体的实现。必须指出的是,这个接口不一定和抽象化角色的接口定义相同,实际上,这两个接口可以非常不一样。实现化角色应当只给出底层操作,而抽象化角色应当只给出基于底层操作的更高一层的操作。

(4)、具体实现化角色(Concrete Implementor):这个角色给出实现化角色接口的具体实现。

  在桥接模式中,两个类Abstraction和Implementor分别定义了抽象与行为类型的接口,通过调用两接口的子类实现抽象与行为的动态组合。

2.5 、桥接模式的具体代码实现

今天我们就以数据库为例来写该模式的实现。每种数据库都有自己的版本,但是每种数据库在不同的平台上实现又是不一样的。比如:微软的SqlServer数据库,该数据库它有2000版本、2005版本、2006版本、2008版本,后面还会有更新的版本。并且这些版本都是运行在Windows操作系统下的,如果要提供Lunix操作系统下的SqlServer怎么办呢?如果又要提供IOS操作系统下的SqlServer数据库该怎么办呢?这个情况就可以使用桥接模式,也就是Brige模式。我们就来看看具体的实现吧!

 namespace 桥接模式的实现
{
/// <summary>
/// 该抽象类就是抽象接口的定义,该类型就相当于是Abstraction类型
/// </summary>
public abstract class Database
{
//通过组合方式引用平台接口,此处就是桥梁,该类型相当于Implementor类型
protected PlatformImplementor _implementor; //通过构造器注入,初始化平台实现
protected Database(PlatformImplementor implementor)
{
this._implementor = implementor;
} //创建数据库--该操作相当于Abstraction类型的Operation方法
public abstract void Create();
} /// <summary>
/// 该抽象类就是实现接口的定义,该类型就相当于是Implementor类型
/// </summary>
public abstract class PlatformImplementor
{
//该方法就相当于Implementor类型的OperationImpl方法
public abstract void Process();
} /// <summary>
/// SqlServer2000版本的数据库,相当于RefinedAbstraction类型
/// </summary>
public class SqlServer2000 : Database
{
//构造函数初始化
public SqlServer2000(PlatformImplementor implementor) : base(implementor) { } public override void Create()
{
this._implementor.Process();
}
} /// <summary>
/// SqlServer2005版本的数据库,相当于RefinedAbstraction类型
/// </summary>
public class SqlServer2005 : Database
{
//构造函数初始化
public SqlServer2005(PlatformImplementor implementor) : base(implementor) { } public override void Create()
{
this._implementor.Process();
}
} /// <summary>
/// SqlServer2000版本的数据库针对Unix操作系统具体的实现,相当于ConcreteImplementorA类型
/// </summary>
public class SqlServer2000UnixImplementor : PlatformImplementor
{
public override void Process()
{
Console.WriteLine("SqlServer2000针对Unix的具体实现");
}
} /// <summary>
/// SqlServer2005版本的数据库针对Unix操作系统的具体实现,相当于ConcreteImplementorB类型
/// </summary>
public sealed class SqlServer2005UnixImplementor : PlatformImplementor
{
public override void Process()
{
Console.WriteLine("SqlServer2005针对Unix的具体实现");
}
} public class Program
{
static void Main()
{
PlatformImplementor SqlServer2000UnixImp = new SqlServer2000UnixImplementor();
//还可以针对不同平台进行扩展,也就是子类化,这个是独立变化的 Database SqlServer2000Unix = new SqlServer2000(SqlServer2000UnixImp);
//数据库版本也可以进行扩展和升级,也进行独立的变化。 //以上就是两个维度的变化。 //就可以针对Unix执行操作了
SqlServer2000Unix.Create();
}
}
}

代码都很简单,也有详细的备注,就不多说了。

三、桥接模式的实现要点:
    
    1.Bridge模式使用“对象间的组合关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。

2.所谓抽象和实现沿着各自维度的变化,即“子类化”它们,得到各个子类之后,便可以任意组合它们,从而获得不同平台上的不同型号。

3.Bridge模式有时候类似于多继承方案,但是多继承方案往往违背了类的单一职责原则(即一个类只有一个变化的原因),复用性比较差。Bridge模式是比多继承方案更好的解决方法。

4.Bridge模式的应用一般在“两个非常强的变化维度”,有时候即使有两个变化的维度,但是某个方向的变化维度并不剧烈——换言之两个变化不会导致纵横交错的结果,并不一定要使用Bridge模式。

    3.1】、桥接模式的优点:

(1)、把抽象接口与其实现解耦。

(2)、抽象和实现可以独立扩展,不会影响到对方。

(3)、实现细节对客户透明,对用于隐藏了具体实现细节。

   3.2】、桥接模式的缺点:

(1)、增加了系统的复杂度

   3.3】、桥接模式的使用场景:

(1)、如果一个系统需要在构件的抽象化角色和具体化角色之间添加更多的灵活性,避免在两个层次之间建立静态的联系。

(2)、设计要求实现化角色的任何改变不应当影响客户端,或者实现化角色的改变对客户端是完全透明的。

(3)、需要跨越多个平台的图形和窗口系统上。

(4)、 一个类存在两个独立变化的维度,且两个维度都需要进行扩展。

四、.NET 中桥接模式的实现

学习中。。。,如果谁有好的代码分享,也可以贴出来。

五、总结

今天的文章就写到这里了,现在小结一下。桥接模式它是连接客户端代码和具体实现代码的一座桥梁,同时它也隔离了实现代码的改变对客户代码的影响。在【意图】中所说的抽象和实现,这两个部分其实都是高度抽象的,前面“抽象”是指定义的针对客户端的接口,客户端其实使用的是Abstract类型或者是RefinedAbstract类型,这两个类型只是接口,具体的实现委托给了Implementor类型了,Abstract类型子类化的扩展也演变成Implementor子类化的变化。我个人的理解,Abstract类型和其子类型在客户端代码和真正实现的代码之间起到了桥梁的作用,隔离了Implementor实现代码的变化,让客户端更稳定,所以【意图】才说是讲抽象部分和它的实现部分隔离。大家好好理解一下吧,刚开始有点绕。

C#设计模式之七桥接模式(Bridge Pattern)【结构型】的更多相关文章

  1. 乐在其中设计模式(C#) - 桥接模式(Bridge Pattern)

    原文:乐在其中设计模式(C#) - 桥接模式(Bridge Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 桥接模式(Bridge Pattern) 作者:webabcd 介绍 ...

  2. 【设计模式】桥接模式 Bridge Pattern

    开篇还是引用吕振宇老师的那篇经典的文章<设计模式随笔-蜡笔与毛笔的故事>.这个真是太经典了,没有比这个例子能更好的阐明桥接模式了,这里我就直接盗来用了. 现在市面上卖的蜡笔很多,各种型号, ...

  3. python 设计模式之桥接模式 Bridge Pattern

    #写在前面 前面写了那么设计模式了,有没有觉得有些模式之间很类似,甚至感觉作用重叠了,模式并不是完全隔离和独立的,有的模式内部其实用到了其他模式的技术,但是又有自己的创新点,如果一味地认为每个模式都是 ...

  4. 二十四种设计模式:桥接模式(Bridge Pattern)

    桥接模式(Bridge Pattern) 介绍将抽象部分与它的实现部分分离,使它们都可以独立地变化. 示例有一个Message实体类,对它的操作有Insert()和Get()方法,现在使这些操作的抽象 ...

  5. 跟着实例学习设计模式(9)-桥接模式bridge(结构型)

    桥接模式属于结构型设计模式. 设计意图:将抽象部分与实现部分分离.使它们都能够独立的变化. 一看到设计意图,大家可能有些发懵,我们看到的继承和接口不都是抽象和实现分离的吗?尤其是接口和抽象类都是这种实 ...

  6. 设计模式--桥接模式Bridge(结构型)

    一.概述 在软件系统中,某些类型由于自身的逻辑,它具有两个或者多个维度的变化,如何应对这种"多维度的变化",就可以利用桥接模式. 引例: 设想如果要绘制矩形.圆形.椭圆.正方形,我 ...

  7. 桥接模式(Bridge Pattern)

    1,定义           桥接模式(Bridge Pattern),也称为桥梁模式,其用意是将抽象化与实现化脱耦,使得两者可以独立的变化,它可以使软件系统沿着多个方向进行变化,而又不引入额外的复杂 ...

  8. 设计模式(六)桥连模式Bridge(结构型)

      设计模式(六)桥连模式Bridge(结构型) 1. 概述 在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够 ...

  9. Net设计模式实例之桥接模式( Bridge Pattern)

    一.桥接模式简介(Brief Introduction) 桥接模式(Bridge Pattern),将抽象部分与它的实现部分分离,使的抽象和实现都可以独立地变化. Decouple an abstra ...

随机推荐

  1. Redis Cluster [WARNING] Node 127.0.0.1:7003 has slots in migrating state (15495).

    错误描述 在迁移一个节点上的slot到另一个节点的时候卡在其中的一个slot报错,截图如下: 查询发现在15495的这个slot上面存在一个key,但是并没有发现这个key有什么问题.使用fix进行修 ...

  2. 剑指offer面试题26:复杂链表的复制

    题目:请实现一个函数,复制一个复杂链表. 在复杂链表中,每个结点除了有一个next指针指向下一个结点外,还有一个sibling指针指向链表中的任意结点或者nulL 直观解法: 1.遍历链表,复制链表节 ...

  3. springDatasolr 排序

    String sortValue = (String) searchMap.get("sort");// ASC DESC String sortField = (String) ...

  4. 如何将自己的jar包发布到mavan中央仓库

    最近自己写了一个关于网关限流的插件,然后想着肯定会有很多兄弟也需要使用到,所以就想着把jar包上传到Maven的中央仓库上让大家可以更方便的使用 现在咱们来看一下这个流程是什么样的呢. 首先呢,你得去 ...

  5. 几分钟几张图教你学会如何使用UML

    很多初次接触UML的朋友们可能会感觉它各种各样的线条.关系.描述等晦涩难懂.本篇文章简单介绍了一下其中几个图,用最朴实的语言结合上图片来让你一眼就能理解他们,如果您在阅读的过程种发现错误之处恳请您在评 ...

  6. 第61节:Java中的DOM和Javascript技术

    Java中的DOM和Javascript技术 DOM是一门技术,是文档对象模型.所需的文档只有标记型文档,如我们所学的html文档(文档中的所有标签都封装成为对象了) DOM: 为Document O ...

  7. shell 中的单行注释和多行注释

    1. 单行注释 众所周知,#  比如想要注释:echo “ni” # echo "ni" 2. 多行注释: 法一: : << ! 语句1 语句2 语句3 语句4 ! 例 ...

  8. JAVA基础-输入输出流

    一,File类:文件的创建和删除 1.File(String pathname):pathname是指路径名称.用法 File file = new File("d:/1.txt " ...

  9. 破解第二课 JMP法

    首先,我用录屏大师自制了一个视频,给视频加上密码.任意输入,看到报错信息“密码不对,请重新输入” 第一步 反汇编窗口右键点击“中文搜索引擎”---“智能搜索”,搜索引擎界面再次搜索“不对”,结果如下: ...

  10. 1.Git起步-Git的三种状态以及三种工作区域、CVCS与DVCS的区别、Git基本工作流程

    1.Git基础 版本控制系统是一种用于记录一个或多个文件内容变化,以便将来查阅恢复特定版本修订情况的系统. Git是一种分布式版本控制系统(Distributed Version Control Sy ...