问题描述

现在要去画一个图形,图形有长方形、圆形和扇形等等;而图形又可以加上不同的颜色,然后,我们就可以画出红色的长方形,绿色的长方形;红色的圆形,绿色的圆形等等。而这种图形的形状在变化,图形的颜色也在变化,当使用代码去实现时,如何面对这种多方面的变化呢?这就要说到今天的桥接模式了。

什么是桥接模式?

对于上述的图形与颜色的问题时,很多时候,我们让各个图形类继承颜色类,比如:

 class CShape
{
};
class CRectangle : public CShape
{
};
class CCircle : public CShape
{
};
class CColor
{
};
class CRed : public CColor
{
};
class CBlue : public CColor
{
};
class CRedRectangle : public CRed
{
};
class CBlueRectangle : public CBlue
{
};

每当我们增加一个新的图形,或者增加一种新的颜色时,对应的类就会以相乘的速度进行增加。当系统中的类变的多时,对应的管理也就变的复杂,这不是我们希望看到的。同时,我们可以看到CRedRectangle类继承自CRed类,这种继承关系合理吗?且不说有的系统是如此实现的,红色的矩形是红色吗?很显然,CRedRectangle和CRed之间不是一种is-a的关系,所以,上面的实现是及其不合理的。那么它们是什么关系呢?接着往下看。

在GOF的《设计模式:可复用面向对象软件的基础》一书中对桥接模式是这样说的:将抽象部分和它的实现部分分离,使它们都可以独立的变化。简单粗暴的说,就是抽象对外提供调用的接口;对外隐瞒实现部分,在抽象中引用实现部分,从而实现抽象对实现部分的调用,而抽象中引用的实现部分可以在今后的开发过程中,切换成别的实现部分。

为什么要使用桥接模式?

当一个抽象可能有多个实现时,通常用继承来协调它们。抽象类定义对该抽象的接口,而具体的子类则用不同方式加以实现。但是此方法有时不够灵活。继承机制将抽象部分与它的实现部分固定在一起,使得难以对抽象部分和实现部分独立的进行修改、扩充和重用。桥接模式把依赖具体实现,提升为依赖抽象,来完成对象和变化因素之间的低耦合,提高系统的可维护性和扩展性。桥接模式的主要目的是将一个对象的变化与其它变化隔离开,让彼此之间的耦合度最低。

什么时候使用桥接模式?

  1. 如果不希望在抽象和它的实现部分之间有一个固定的绑定关系,也就是继承关系;如果我们打破了这种固定的绑定关系,以后,就可以方便的在抽象部分切换不同的实现部分;
  2. 如果希望类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充;如果不使用桥接模式,使用继承去实现时,在抽象类中添加一个方法,则在对应的实现类中也需要做对应的改动,这种实现不符合松耦合的要求;
  3. 如果要求对一个抽象的实现部分的修改对客户不产生影响,即客户的代码不需要重新编译,在后面的项目经验会说这方面;
  4. 如果想对客户完全隐藏抽象的实现部分;
  5. 如果一个对象有多个变化因素的时候,通过抽象这些变化因素,将依赖具体实现,修改为依赖抽象;
  6. 如果某个变化因素在多个对象中共享时,可以抽象出这个变化因素,然后实现这些不同的变化因素。

上面使用的场景,是一种建议,也是一种参考。在项目中要很好的把握一个设计模式,是有一定的难度的;当在实际项目中遇到满足上面的一点或者几点时,可以考虑使用桥接模式。

UML类图

Abstraction类定义了抽象类的接口,并且维护一个指向Implementor实现类的指针;

RefineAbstraction类扩充了Abstraction类的接口;

Implementor类定义了实现类的接口,这个接口不一定要与Abstraction的接口完全一致;实际上,这两个接口可以完全不同;

ConcreteImplementor类实现了Implementor定义的接口。

代码实现

 #include <iostream>
using namespace std;
class Implementor
{
public:
virtual void OperationImpl() = ;
};
class ConcreteImpementor : public Implementor
{
public:
void OperationImpl()
{
cout<<"OperationImpl"<<endl;
}
};
class Abstraction
{
public:
Abstraction(Implementor *pImpl) : m_pImpl(pImpl){}
virtual void Operation() = ;
protected:
Implementor *m_pImpl;
};
class RedfinedAbstraction : public Abstraction
{
public:
RedfinedAbstraction(Implementor *pImpl) : Abstraction(pImpl){}
void Operation()
{
m_pImpl->OperationImpl();
}
};
int main(int argc, char *argv[])
{
Implementor *pImplObj = new ConcreteImpementor();
Abstraction *pAbsObj = new RedfinedAbstraction(pImplObj);
pAbsObj->Operation();
delete pImplObj;
pImplObj = NULL;
delete pAbsObj;
pAbsObj = NULL;
return ;
}

根据对代码的理解,能想象到CRedRectangle和CRed是什么关系吗?我们可以理解为红色的矩形包含红色,也就是包含的关系,也就是软件设计中的组合关系(has-a)。

项目经验

这是一个我经历的项目,也是做起来比较轻松的一个项目。项目是这样的,需要对一个中间的通信库进行改写,保留以前的通信方式的同时,需要使用一种新的通信协议去和底层模块进行通信。现有的代码是一个COM程序,向外提供了可以调用的接口。根据客户提供的源码,我们进行了分析;在分析之前,我们有一种担心,就是怕用户的代码是接口和实现混在一起的;但是,分析之后,让我们很吃惊,客户的代码结构很清晰,层次非常清楚,代码中使用的就是我们今天这里说的桥接模式。由于抽象的接口和实现完全进行了分离,我们在进行重写时,只需要实现我们的一个类,然后在接口中引用我们实现的类,就大功告成了,这样做到了客户端不需要做任何修改,就可以完美的替换掉原来的通信层,真的是前人栽树树,后人乘凉啊。

总结

桥接模式使得抽象和实现进行了分离,抽象不用依赖于实现,让抽象和实现部分各自修改起来都很方便,使用组合(就是Abstraction类中包含了Implementor)的方式,降低了耦合度,同时也有助于分层,从而产生更好的结构化系统。通过实际的项目经验,使用了桥接模式的代码,对以后的扩展有很大的帮助。

C++设计模式——桥接模式的更多相关文章

  1. 转:设计模式-----桥接模式(Bridge Pattern)

    转自:http://www.cnblogs.com/houleixx/archive/2008/02/23/1078877.html 记得看原始链接的评论. 学习设计模式也有一段时间了,今天就把我整理 ...

  2. 跟着ZHONGHuan学习设计模式--桥接模式

    转载请注明出处! ! !http://blog.csdn.net/zhonghuan1992 全部配套代码均在github上:https://github.com/ZHONGHuanGit/Desig ...

  3. linkin大话设计模式--桥接模式

    linkin大话设计模式--桥接模式 桥接模式是一种结构化模式,他主要应对的是:由于实际的需要,某个类具有2个或者2个以上维度的变化,如果只是使用继承将无法实现功能,或者会使得设计变得相当的臃肿.我们 ...

  4. java设计模式——桥接模式

    一. 定义与类型 定义:将抽象部分与他的具体实现部分分离,使它们都可以独立的变化,通过组合的方式建立两个类之间的联系,而不是继承 类型:结构性. 二. 使用场景 (1) 抽象和具体实现之间增加更多的灵 ...

  5. 【设计模式】Java设计模式 - 桥接模式

    [设计模式]Java设计模式 - 桥接模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 原创作品,更多关注我CSDN: 一个有梦有戏的人 准备将博客园.CSDN一起 ...

  6. JAVA 设计模式 桥接模式

    用途 桥接模式 (Bridge) 将抽象部分与实现部分分离,使它们都可以独立的变化. 桥接模式是一种结构式模式. 结构

  7. javascript设计模式-桥接模式

    在系统中,某些类由于自身逻辑,具有两个或两个以上维度的变化,如何使得该类型可以沿多个方向变化,但又不引入额外的复杂度,这就是桥接模式要解决的问题. 定义:桥接模式(Bridge),将抽象部分与它的实现 ...

  8. 设计模式 -- 桥接模式(Bridge Pattern)

    桥接模式 Bridge Pattern 结构设计模式 定义: 分离抽象部分和实现部分,使他们独立运行. 避免使用继承导致系统类个数暴增,可以考虑桥接模式. 桥接模式将继承关系转化为关联关系,减少耦合, ...

  9. [Unity 设计模式]桥接模式(BridgePattern)

    1.前言 继上一讲IOC模式的基础上继续本讲桥接模式,笔者感觉桥接模式是23种设计模式中桥接模式是最好用但也是最难理解的设计模式之一,23中设计模式就好武侠剧中一本武功秘籍,我们在工作过程中想要熟练运 ...

  10. 结合JDK源码看设计模式——桥接模式

    前言: 在我们还没学习框架之前,肯定都学过JDBC.百度百科对JDBC是这样介绍的[JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Jav ...

随机推荐

  1. .net后台以post方式调用http接口[转]

    string strResult = ""; try { HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create( ...

  2. sklearn.linear_model.LogisticRegression参数说明

    目录 sklearn.linear_model.LogisticRegression sklearn.linear_model.LogisticRegressionCV sklearn.linear_ ...

  3. 【原创】JAVA面试解析(有赞一面)

    本文的题目出自博客 http://www.54tianzhisheng.cn/2018/07/12/youzan/ 但是作者没有给出答案,博主斗胆来制作答案版. 引言 说在前面的话: 本文适合人群:急 ...

  4. 5行代码实现微信小程序图片上传与腾讯免费5G存储空间的使用

    本文介绍了如何在微信小程序开发中使用腾讯官方提供的云开发功能快速实现图片的上传与存储,以及介绍云开发的 5G 存储空间的基本使用方法,这将大大提高微信小程序的开发效率,同时也是微信小程序系列教程的视频 ...

  5. 一个方法教你认识ref(简单易懂)

    参数分为值类型和引用类型,当我们将一个值类型的参数进行传递到另一个方法的时候相当于,将这个变量进行复制到该方法进行操作,但是不会对该变量原始的值有影响. 但是有时候我们需要他有“影响”于是ref就出现 ...

  6. 一个.net的程序员如何转到java的?

    先说明,大佬请忽略我这篇文章, 我是一个做了5年的纯种C#开发人,  我在此仅记录一下我转java的过程.都知道, java是开源的,所以它的开发工具贼多,不像.net, 直接地表最强的IDE. 像现 ...

  7. PS调出米黄色复古柔和外景人物照

    配色思路 从片中可以看出主要景物近处的有人物和栏杆,远处的海水,天空和礁石.为体现出远近层次,近处景物选择了偏黄的色调,远处景物选择了偏青色调. 调色 以下面这张照片为例,先放上对比图: LR部分 首 ...

  8. rsync用法详细解释

    提要 熟悉 rsync 的功能及其特点 掌握 rsync 语法及常用选项的功能 掌握 rsync 命令的三种基本使用方法 掌握如何筛选 rsync 的传输目标 掌握使用 rsync 进行镜像和增量备份 ...

  9. centos7之NFS使用

    NFS是Network File System的缩写,即网络文件系统.客户端通过挂载的方式将NFS服务器端共享的数据目录挂载到本地目录下. 一.nfs为什么需要RPC? 因为NFS支持的功能很多,不同 ...

  10. const 本质

    const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动.对于简单类型的数据(数值.字符串.布尔值),值就保存在变量指向的那个内存地址,因此等同于常量.但对于复合类型的数据( ...