C++设计模式之桥接模式
问题描述
现在要去画一个图形,图形有长方形、圆形和扇形等等;而图形又可以加上不同的颜色,然后,我们就可以画出红色的长方形,绿色的长方形;红色的圆形,绿色的圆形等等。而这种图形的形状在变化,图形的颜色也在变化,当使用代码去实现时,如何面对这种多方面的变化呢?这就要说到今天的桥接模式了。
什么是桥接模式?
对于上述的图形与颜色的问题时,很多时候,我们让各个图形类继承颜色类,比如:
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定义的接口。
代码实现
/*
** FileName : BridgePatternDemo
** Author : Jelly Young
** Date : 2013/12/4
** Description : More information, please go to http://www.jb51.net
*/
#include <iostream>
using namespace std;
class Implementor
{
public:
virtual void OperationImpl() = 0;
};
class ConcreteImpementor : public Implementor
{
public:
void OperationImpl()
{
cout<<"OperationImpl"<<endl;
}
};
class Abstraction
{
public:
Abstraction(Implementor *pImpl) : m_pImpl(pImpl){}
virtual void Operation() = 0;
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 0;
}
根据对代码的理解,能想象到CRedRectangle和CRed是什么关系吗?我们可以理解为红色的矩形包含红色,也就是包含的关系,也就是软件设计中的组合关系(has-a)。
项目经验
这是一个我经历的项目,也是做起来比较轻松的一个项目。项目是这样的,需要对一个中间的通信库进行改写,保留以前的通信方式的同时,需要使用一种新的通信协议去和底层模块进行通信。现有的代码是一个COM程序,向外提供了可以调用的接口。根据客户提供的源码,我们进行了分析;在分析之前,我们有一种担心,就是怕用户的代码是接口和实现混在一起的;但是,分析之后,让我们很吃惊,客户的代码结构很清晰,层次非常清楚,代码中使用的就是我们今天这里说的桥接模式。由于抽象的接口和实现完全进行了分离,我们在进行重写时,只需要实现我们的一个类,然后在接口中引用我们实现的类,就大功告成了,这样做到了客户端不需要做任何修改,就可以完美的替换掉原来的通信层,真的是前人栽树树,后人乘凉啊。
总结
桥接模式使得抽象和实现进行了分离,抽象不用依赖于实现,让抽象和实现部分各自修改起来都很方便,使用组合(就是Abstraction类中包含了Implementor)的方式,降低了耦合度,同时也有助于分层,从而产生更好的结构化系统。通过实际的项目经验,使用了桥接模式的代码,对以后的扩展有很大的帮助。
===================================================================
- /*
- 桥接模式:将抽象部分与它的实现部分相分离,他们可以独立变化。
- 合成/聚合复用原则CARP原则:面向对象设计的一个重要原则:
- 尽量使用合成/聚合,尽量不用使用类的继承
- 优点:
- (1)分离抽象接口及其实现部分。
- (2)桥接模式有时类似于多继承方案,但是多继承方案违背了类的单一职责原则
- (即一个类只有一个变化的原因),复用性比较差,而且多继承结构中类的
- 个数非常庞大,桥接模式是比多继承方案更好的解决方法。
- (3)桥接模式提高了系统的可扩充性,在两个变化维度中任意扩展一个维度,都
- 不需要修改原有系统。
- (4)实现细节对客户透明,可以对用户隐藏实现细节。
- 应用举例:
- 一个画板的形状可以是圆形的,正方形的,颜色可以是红色,绿色,
- 那要求一个实现一个画板就可以采用桥接模式
- Created by Phoenix_FuliMa
- */
- #include <iostream>
- using namespace std;
- class Implementor
- {
- public:
- virtual void Show() {}
- };
- class Implementor1:public Implementor
- {
- public:
- virtual void Show()
- {
- cout<<"Implementor1 is showing..."<<endl;
- }
- };
- class Implementor2: public Implementor
- {
- public:
- virtual void Show()
- {
- cout<<"Implementor2 is showing.."<<endl;
- }
- };
- class Abstractor
- {
- Implementor *_implementor;
- public:
- virtual void SetImplementor(Implementor* ot)
- {
- this->_implementor = ot;
- }
- virtual void operate()
- {
- _implementor->Show();
- }
- };
- class RefinedAbstractor:public Abstractor
- {
- };
- int main()
- {
- Implementor1 * im1 = new Implementor1();
- Implementor2 * im2 = new Implementor2();
- RefinedAbstractor *re = new RefinedAbstractor();
- re->SetImplementor(im1);
- re->operate();
- re->SetImplementor(im2);
- re->operate();
- delete im1;
- delete im2;
- delete re;
- system("pause");
- return 0;
- }
C++设计模式之桥接模式相关推荐
- java桥接和装饰_设计模式:桥接模式和装饰模式
原标题:设计模式:桥接模式和装饰模式 一.桥接模式简介 1.基础描述 桥梁模式是对象的结构模式.又称为柄体(Handle and Body)模式或接口(Interface)模式.桥梁模式的用意是&qu ...
- php设计模式之桥接模式
php设计模式之桥接模式 一.概述 桥接模式:将两个原本不相关的类结合在一起,然后利用两个类中的方法和属性,输出一份新的结果. 其实就是讲不相关的东西通过类(本例中是SendInfo)结合在一起,从而 ...
- java 懒加载模式_JavaScript面试系列:JavaScript设计模式之桥接模式和懒加载
我写的程序员面试系列文章 Java面试系列-webapp文件夹和WebContent文件夹的区别? 程序员面试系列:Spring MVC能响应HTTP请求的原因? Java程序员面试系列-什么是Jav ...
- 详解设计模式:桥接模式
桥接模式(Bridge Pattern)也称为桥梁模式.接口模式或者柄体模式,有点像适配器模式,也是 GoF 的 23 种设计模式中的一种结构型设计模式. 桥接模式 是用于把抽象化与实现化解耦,使得二 ...
- 设计模式之桥接模式详解
设计模式之桥接模式详解 文章目录 设计模式之桥接模式详解 一.什么是桥接模式 二.桥接模式的应用场景 三.桥接模式的角色组成 四.桥接模式通用写法示例 五.桥接模式优缺点 一.什么是桥接模式 桥接模式 ...
- 如何让孩子爱上设计模式 ——10.桥接模式(Bridge Pattern)
如何让孩子爱上设计模式 --10.桥接模式(Bridge Pattern) 标签: 设计模式初涉 我有故事,你有酒吗?这年头写个技术文不讲个故事都不行,行,我讲: 还有发现很多的技术博文都开始有喜欢往 ...
- java 设计模式之桥接模式,策略模式
java 设计模式之桥接模式,策略模式 1.引出设计模式 相信大家都玩过王者荣耀这款游戏.我们知道现在大概有九十多个英雄且各自技能及背景故事.台词.被动都不一样而且还带着召唤师技能比如实现,惩戒,弱化 ...
- 《设计模式》桥接模式
<设计模式>设计模式的基本原则 <设计模式>单例模式 <设计模式>工厂模式 <设计模式>原型模式 <设计模式>建造者模式 <设计模式& ...
- 设计模式之桥接模式(Bridge)摘录
23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式包括:1.FactoryMethod(工厂方法模式):2.Abstract Factory(抽象工厂模式):3.Sin ...
最新文章
- node 多进程 vs java_node多进程服务器
- 5.MYSQL存储过程的管理
- js访问对方手机文件夹_求JS大神帮我写个利用JS来实现手机端和PC端访问自动选择样式文件代码...
- webapi输出炜json_webapi转化为json格式
- 使用 gradle 在编译时动态设置 Android resValue / BuildConfig / Manifes中lt;meta-datagt;变量的值...
- SpringBoot之集成MybatisPlus
- MySQL抽稀_Android GPS定位轨迹抽稀之道格拉斯-普克(Douglas-Peuker)算法详解
- python字典练习_python字典练习
- C语言 常用标准库函数 初学者常用
- 黑苹果intel 9560ac网卡成功驱动,无需换卡
- (附源码)springboot西安市中小学生护眼平台开发 毕业设计 080855
- 20220906_C52单片机学习笔记 | LED闪烁
- DW2019HTML中没有文本对象,Dreamweaver CC2019文字或图片添加空连接方法
- Mysql 按当天、当月、上月及按日期范围查询 DATE_FORMAT( date, ‘%Y%m‘ )
- 图像超分辨率技术简介
- orocos安装_动脑共享单车环境搭建
- 【机器学习实战笔记】Logistic回归
- Android 强大的图片加载缓存— Glide
- 对于2019全国高速公路视频联网工作实施方案的理解:视频上云网关与省级视频云平台
- 【Qt】QMainWindow |QDialog对话框