C++设计模式-Bridge桥接模式
作用:将抽象部份与它的实现部份分离,使它们都可以独立地变化。
将抽象(Abstraction)与实现(Implementation)分离,使得二者可以独立地变化。
桥接模式号称设计模式中最难理解的模式之一,关键就是这个抽象和实现的分离非常让人奇怪,大部分人刚看到这个定义的时候都会认为实现就是继承自抽象,那怎么可能将他们分离呢。
《大话设计模式》中就Bridge模式的解释:
手机品牌和软件是两个概念,不同的软件可以在不同的手机上,不同的手机可以有相同的软件,两者都具有很大的变动性。如果我们单独以手机品牌或手机软件为基类来进行继承扩展的话,无疑会使类的数目剧增并且耦合性很高,(如果更改品牌或增加软件都会增加很多的变动)两种方式的结构如下:
所以将两者抽象出来两个基类分别是PhoneBrand和PhoneSoft,那么在品牌类中聚合一个软件对象的基类将解决软件和手机扩展混乱的问题,这样两者的扩展就相对灵活,剪短了两者的必要联系,结构图如下:
这样扩展品牌和软件就相对灵活独立,达到解耦的目的!
UML结构图如下:
抽象基类及接口:
1、Abstraction::Operation():定义要实现的操作接口
2、AbstractionImplement::Operation():实现抽象类Abstaction所定义操作的接口,由其具体派生类ConcreteImplemenA、ConcreteImplemenA或者其他派生类实现。
3、在Abstraction::Operation()中根据不同的指针多态调用AbstractionImplement::Operation()函数。
理解:
Bridge用于将表示和实现解耦,两者可以独立的变化.在Abstraction类中维护一个AbstractionImplement类指针,需要采用不同的实现方式的时候只需要传入不同的AbstractionImplement派生类就可以了.
Bridge的实现方式其实和Builde十分的相近,可以这么说:本质上是一样的,只是封装的东西不一样罢了.两者的实现都有如下的共同点:
抽象出来一个基类,这个基类里面定义了共有的一些行为,形成接口函数(对接口编程而不是对实现编程),这个接口函数在Buildier中是BuildePart函数在Bridge中是Operation函数;
其次,聚合一个基类的指针,如Builder模式中Director类聚合了一个Builder基类的指针,而Brige模式中Abstraction类聚合了一个AbstractionImplement基类的指针(优先采用聚合而不是继承);
而在使用的时候,都把对这个类的使用封装在一个函数中,在Bridge中是封装在Director::Construct函数中,因为装配不同部分的过程是一致的,而在Bridge模式中则是封装在Abstraction::Operation函数中,在这个函数中调用对应的AbstractionImplement::Operation函数.就两个模式而言,Builder封装了不同的生成组成部分的方式,而Bridge封装了不同的实现方式.
桥接模式就将实现与抽象分离开来,使得RefinedAbstraction依赖于抽象的实现,这样实现了依赖倒转原则,而不管左边的抽象如何变化,只要实现方法不变,右边的具体实现就不需要修改,而右边的具体实现方法发生变化,只要接口不变,左边的抽象也不需要修改。
常用的场景
1.当一个对象有多个变化因素的时候,考虑依赖于抽象的实现,而不是具体的实现。如上面例子中手机品牌有2种变化因素,一个是品牌,一个是功能。
2.当多个变化因素在多个对象间共享时,考虑将这部分变化的部分抽象出来再聚合/合成进来,如上面例子中的通讯录和游戏,其实是可以共享的。
3.当我们考虑一个对象的多个变化因素可以动态变化的时候,考虑使用桥接模式,如上面例子中的手机品牌是变化的,手机的功能也是变化的,所以将他们分离出来,独立的变化。
优点
1.将实现抽离出来,再实现抽象,使得对象的具体实现依赖于抽象,满足了依赖倒转原则。
2.将可以共享的变化部分,抽离出来,减少了代码的重复信息。
3.对象的具体实现可以更加灵活,可以满足多个因素变化的要求。
缺点
1.客户必须知道选择哪一种类型的实现。
设计中有超过一维的变化我们就可以用桥模式。如果只有一维在变化,那么我们用继承就可以圆满的解决问题。
代码如下:
Abstraction.h
1 #ifndef _ABSTRACTION_H_ 2 #define _ABSTRACTION_H_ 3 4 class AbstractionImplement; 5 6 class Abstraction 7 { 8 public: 9 virtual void Operation()=0;//定义接口,表示该类所支持的操作 10 virtual ~Abstraction(); 11 protected: 12 Abstraction(); 13 }; 14 15 class RefinedAbstractionA:public Abstraction 16 { 17 public: 18 RefinedAbstractionA(AbstractionImplement* imp);//构造函数 19 virtual void Operation();//实现接口 20 virtual ~RefinedAbstractionA();//析构函数 21 private: 22 AbstractionImplement* _imp;//私有成员 23 }; 24 25 class RefinedAbstractionB:public Abstraction 26 { 27 public: 28 RefinedAbstractionB(AbstractionImplement* imp);//构造函数 29 virtual void Operation();//实现接口 30 virtual ~RefinedAbstractionB();//析构函数 31 private: 32 AbstractionImplement* _imp;//私有成员 33 }; 34 #endif
Abstraction.cpp
1 #include "Abstraction.h" 2 #include "AbstractionImplement.h" 3 #include <iostream> 4 5 using namespace std; 6 7 Abstraction::Abstraction() 8 {} 9 10 Abstraction::~Abstraction() 11 {} 12 13 RefinedAbstractionA::RefinedAbstractionA(AbstractionImplement* imp) 14 { 15 this->_imp = imp; 16 } 17 18 RefinedAbstractionA::~RefinedAbstractionA() 19 { 20 delete this->_imp; 21 this->_imp = NULL; 22 } 23 24 void RefinedAbstractionA::Operation() 25 { 26 cout << "RefinedAbstractionA::Operation" << endl; 27 this->_imp->Operation(); 28 } 29 30 RefinedAbstractionB::RefinedAbstractionB(AbstractionImplement* imp) 31 { 32 this->_imp = imp; 33 } 34 35 RefinedAbstractionB::~RefinedAbstractionB() 36 { 37 delete this->_imp; 38 this->_imp = NULL; 39 } 40 41 void RefinedAbstractionB::Operation() 42 { 43 cout << "RefinedAbstractionB::Operation" << endl; 44 this->_imp->Operation(); 45 }
AbstractImplement.h
1 #ifndef _ABSTRACTIONIMPLEMENT_H_ 2 #define _ABSTRACTIONIMPLEMENT_H_ 3 4 //抽象基类,定义了实现的接口 5 class AbstractionImplement 6 { 7 public: 8 virtual void Operation()=0;//定义操作接口 9 virtual ~AbstractionImplement(); 10 protected: 11 AbstractionImplement(); 12 }; 13 14 // 继承自AbstractionImplement,是AbstractionImplement的不同实现之一 15 class ConcreteAbstractionImplementA:public AbstractionImplement 16 { 17 public: 18 ConcreteAbstractionImplementA(); 19 void Operation();//实现操作 20 ~ConcreteAbstractionImplementA(); 21 protected: 22 }; 23 24 // 继承自AbstractionImplement,是AbstractionImplement的不同实现之一 25 class ConcreteAbstractionImplementB:public AbstractionImplement 26 { 27 public: 28 ConcreteAbstractionImplementB(); 29 void Operation();//实现操作 30 ~ConcreteAbstractionImplementB(); 31 protected: 32 }; 33 #endif
AbstractImplement.cpp
1 #include "AbstractionImplement.h" 2 #include <iostream> 3 4 using namespace std; 5 6 AbstractionImplement::AbstractionImplement() 7 {} 8 9 AbstractionImplement::~AbstractionImplement() 10 {} 11 12 ConcreteAbstractionImplementA::ConcreteAbstractionImplementA() 13 {} 14 15 ConcreteAbstractionImplementA::~ConcreteAbstractionImplementA() 16 {} 17 18 void ConcreteAbstractionImplementA::Operation() 19 { 20 cout << "ConcreteAbstractionImplementA Operation" << endl; 21 } 22 23 ConcreteAbstractionImplementB::ConcreteAbstractionImplementB() 24 {} 25 26 ConcreteAbstractionImplementB::~ConcreteAbstractionImplementB() 27 {} 28 29 void ConcreteAbstractionImplementB::Operation() 30 { 31 cout << "ConcreteAbstractionImplementB Operation" << endl; 32 }
main.cpp
1 #include "Abstraction.h" 2 #include "AbstractionImplement.h" 3 #include <iostream> 4 5 using namespace std; 6 7 int main() 8 { 9 /* 将抽象部分与它的实现部分分离,使得它们可以独立地变化 10 11 1、抽象Abstraction与实现AbstractionImplement分离; 12 13 2、抽象部分Abstraction可以变化,如new RefinedAbstractionA(imp)、new RefinedAbstractionB(imp2); 14 15 3、实现部分AbstractionImplement也可以变化,如new ConcreteAbstractionImplementA()、new ConcreteAbstractionImplementB(); 16 17 */ 18 19 AbstractionImplement* imp = new ConcreteAbstractionImplementA(); //实现部分ConcreteAbstractionImplementA 20 Abstraction* abs = new RefinedAbstractionA(imp); //抽象部分RefinedAbstractionA 21 abs->Operation(); 22 23 cout << "-----------------------------------------" << endl; 24 25 AbstractionImplement* imp1 = new ConcreteAbstractionImplementB(); //实现部分ConcreteAbstractionImplementB 26 Abstraction* abs1 = new RefinedAbstractionA(imp1); //抽象部分RefinedAbstractionA 27 abs1->Operation(); 28 29 cout << "-----------------------------------------" << endl; 30 31 AbstractionImplement* imp2 = new ConcreteAbstractionImplementA(); //实现部分ConcreteAbstractionImplementA 32 Abstraction* abs2 = new RefinedAbstractionB(imp2); //抽象部分RefinedAbstractionB 33 abs2->Operation(); 34 35 cout << "-----------------------------------------" << endl; 36 37 AbstractionImplement* imp3 = new ConcreteAbstractionImplementB(); //实现部分ConcreteAbstractionImplementB 38 Abstraction* abs3 = new RefinedAbstractionB(imp3); //抽象部分RefinedAbstractionB 39 abs3->Operation(); 40 41 cout << endl; 42 return 0; 43 }
代码说明:
Bridge模式将抽象和实现分别独立实现,在代码中就是Abstraction类和AbstractionImplement类。
使用组合(委托)的方式将抽象和实现彻底地解耦,这样的好处是抽象和实现可以分别独立地变化,系统的耦合性也得到了很好的降低。
GoF的那句话中的“实现”该怎么去理解:“实现”特别是和“抽象”放在一起的时候我们“默认”的理解是“实现”就是“抽象”的具体子类的实现,但是这里GoF所谓的“实现”的含义不是指抽象基类的具体子类对抽象基类中虚函数(接口)的实现,是和继承结合在一起的。而这里的“实现”的含义指的是怎么去实现用户的需求,并且指的是通过组合(委托)的方式实现的,因此这里的实现不是指的继承基类、实现基类接口,而是指的是通过对象组合实现用户的需求。
实际上上面使用Bridge模式和使用带来问题方式的解决方案的根本区别在于是通过继承还是通过组合的方式去实现一个功能需求。
备注:
由于实现的方式有多种,桥接模式的核心就是把这些实现独立出来,让他们各自变化。
将抽象部分与它的实现部分分离:实现系统可能有多角度(维度)分类,每一种分类都可能变化,那么就把这种多角度分离出来让它们独立变化,减少它们之间的耦合。
在发现需要多角度去分类实现对象,而只用继承会造成大量的类增加,不能满足开放-封闭原则时,就要考虑用Bridge桥接模式了。
合成/聚合复用原则:尽量使用合成/聚合,精良不要使用类继承。
优先使用对象的合成/聚合将有助于保持每个类被封装,并被集中在单个任务上。这样类和类继承层次会保持较小规模,并且不太可能增长为不可控制的庞然大物。
C++设计模式-Bridge桥接模式相关推荐
- [php]php设计模式 Bridge (桥接模式)
1 <?php 2 /** 3 * 桥接模式 4 * 5 * 将抽象部份与它实现部分分离,使用它们都可以有独立的变化 6 */ 7 abstractclass Implementor 8 { 9 ...
- 设计模式之桥接模式(Bridge)摘录
23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式包括:1.FactoryMethod(工厂方法模式):2.Abstract Factory(抽象工厂模式):3.Sin ...
- 如何让孩子爱上设计模式 ——10.桥接模式(Bridge Pattern)
如何让孩子爱上设计模式 --10.桥接模式(Bridge Pattern) 标签: 设计模式初涉 我有故事,你有酒吗?这年头写个技术文不讲个故事都不行,行,我讲: 还有发现很多的技术博文都开始有喜欢往 ...
- php设计模式之桥接模式
php设计模式之桥接模式 一.概述 桥接模式:将两个原本不相关的类结合在一起,然后利用两个类中的方法和属性,输出一份新的结果. 其实就是讲不相关的东西通过类(本例中是SendInfo)结合在一起,从而 ...
- 详解设计模式:桥接模式
桥接模式(Bridge Pattern)也称为桥梁模式.接口模式或者柄体模式,有点像适配器模式,也是 GoF 的 23 种设计模式中的一种结构型设计模式. 桥接模式 是用于把抽象化与实现化解耦,使得二 ...
- 设计模式之桥接模式详解
设计模式之桥接模式详解 文章目录 设计模式之桥接模式详解 一.什么是桥接模式 二.桥接模式的应用场景 三.桥接模式的角色组成 四.桥接模式通用写法示例 五.桥接模式优缺点 一.什么是桥接模式 桥接模式 ...
- java 设计模式之桥接模式,策略模式
java 设计模式之桥接模式,策略模式 1.引出设计模式 相信大家都玩过王者荣耀这款游戏.我们知道现在大概有九十多个英雄且各自技能及背景故事.台词.被动都不一样而且还带着召唤师技能比如实现,惩戒,弱化 ...
- java桥接和装饰_设计模式:桥接模式和装饰模式
原标题:设计模式:桥接模式和装饰模式 一.桥接模式简介 1.基础描述 桥梁模式是对象的结构模式.又称为柄体(Handle and Body)模式或接口(Interface)模式.桥梁模式的用意是&qu ...
- C++设计模式之桥接模式
这篇文章主要介绍了C++设计模式之桥接模式,本文讲解了什么是桥接模式.为什么要使用桥接模式.什么时候使用桥接模式等内容,需要的朋友可以参考下 问题描述 现在要去画一个图形,图形有长方形.圆形和扇形等等 ...
最新文章
- 自己搭建个对象存储服务难不难?
- fastjson 1.1.71.android 版本发布,优化部分场景性能
- 大剑无锋之介绍几个常见的网络协议且位于哪一层?【面试推荐】
- linux实时线程调度bug,linux中采用用户级线程模拟实现EDF和RMS两种处理机实时调度算法之改进...
- Java泛型,枚举,注解
- 泰勒级数 快速傅里叶变换(Fast Fourier Transfor FFT)
- java se的api下载_API specification for java SE 1.7
- 华为P50首发麒麟9000L:5nm EUV工艺打造 配置有所缩减
- jQuery函数$(window).load事件
- 大数据分析推动业务增长的方法有哪些
- hdfs-文件上传下载
- 配置好网络文件还是连不上外网
- go语言 读文件最后一行_Go 语言核心文件调试
- 【Python数据分析】用户通话行为分析
- tdr 定位公式_基于土壤热导率定位监测容重的Thermo-TDR技术
- python transforms_pytorch中的transforms模块实例详解
- python怎么读?如何正确的发音?
- 宏观低速物理 '牛顿篇'
- kali下载速度慢_Linux系统软件安装更新下载太慢解决方法(转载)
- 安卓手机如何投屏到电视上_手机如何投屏到电视上?小屏秒变大屏,追剧更享受!...
热门文章
- ffmpeg 转换flv压缩大小_使用ffmpeg进行视频文件转换成FLV整理
- githup用户名密码怎么看_MacBook Pro 开机密码忘记解决方法
- OpenCV中直方图均衡化
- 夜间工作致癌的原因被发现:熬夜破坏了癌症相关基因的节律,导致DNA损伤增加、修复效率降低...
- 好奇心和目标:科学力量的源泉 | Cell编辑部社论
- 你的DNA都会玩摇滚了,你却还是个音痴
- KeyShot 10最新版发布 支持big sur KeyShot 10 Pro for Mac新功能
- 信奥中的数学:信息论基础
- 程序猿的数学:scratch篇
- php通过使用curl获取http或者https的响应信息的方式