设计模式---单一职责模式之桥模式(Bridge)
一:概念
Bridge模式又叫做桥接模式,其实基于类的最小设计原则,通过使用封装,聚合以及继承等行为来让不同的类承担不同的责任他的主要特点是吧抽象与行为实现分离开来,从而可以保持各部分的独立性以及一对他们的功能扩展
二:动机
由于某些类型的固有的实现逻辑,使得它们具有两个变化的维度,乃至多个维度的变化。
如何应对这种“多维度的变化”?如何利用面向对象技术来使得类型可以轻松地沿着两个乃至多个方向变化,而不引入额外的复杂度?
三:代码讲解(通信)
和Decorator模式非常像,所以我们需要注意区别
(一)原代码
class Messager{
public:
virtual void Login(string username, string password)=;
virtual void SendMessage(string message)=;
virtual void SendPicture(Image image)=; virtual void PlaySound()=;
virtual void DrawShape()=;
virtual void WriteText()=;
virtual void Connect()=; virtual ~Messager(){}
}; //平台实现PC,Mobile,主要不同是在平台实现上,播放声音,图片绘制,端口写入数据,连接网络上不同。下面的不同注释方式代表不同的实现
class PCMessagerBase : public Messager{
public: virtual void PlaySound(){
//**********
}
virtual void DrawShape(){
//**********
}
virtual void WriteText(){
//**********
}
virtual void Connect(){
//**********
}
}; class MobileMessagerBase : public Messager{
public: virtual void PlaySound(){
//==========
}
virtual void DrawShape(){
//==========
}
virtual void WriteText(){
//==========
}
virtual void Connect(){
//==========
}
}; //业务抽象:在每一种的平台上,我们还要实现不同的功能,比如:经典版,完美版
class PCMessagerLite : public PCMessagerBase {
public: virtual void Login(string username, string password){ PCMessagerBase::Connect(); //调用的基类方法
//........
}
virtual void SendMessage(string message){ PCMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){ PCMessagerBase::DrawShape();
//........
}
}; //功能变多
class PCMessagerPerfect : public PCMessagerBase {
public: virtual void Login(string username, string password){ PCMessagerBase::PlaySound();
//********
PCMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){ PCMessagerBase::PlaySound();
//********
PCMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){ PCMessagerBase::PlaySound();
//********
PCMessagerBase::DrawShape();
//........
}
}; class MobileMessagerLite : public MobileMessagerBase {
public: virtual void Login(string username, string password){ MobileMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){ MobileMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){ MobileMessagerBase::DrawShape();
//........
}
}; class MobileMessagerPerfect : public MobileMessagerBase {
public: virtual void Login(string username, string password){ MobileMessagerBase::PlaySound();
//********
MobileMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){ MobileMessagerBase::PlaySound();
//********
MobileMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){ MobileMessagerBase::PlaySound();
//********
MobileMessagerBase::DrawShape();
//........
}
}; void Process(){
//编译时装配
Messager *m =
new MobileMessagerPerfect();
}
编译时装配:(我们查看Decorator模式中运行时装配)
我们编译时就已经完成了所有的等操作。不同于运行时装配可以通过组合来实现多种方式
我们将平台实现设为n
业务规模设置为m
则上面的最终规模是
+n+n*m
没有组合的情况,但是也是十分恐怖的操作。例如5个平台6个业务就需要36个类
(二)改进业务抽象由继承转组合
class PCMessagerLite{
PCMessagerBase* messager;
public: virtual void Login(string username, string password){ Messager->Connect();
//........
}
virtual void SendMessage(string message){ Messager->WriteText();
//........
}
virtual void SendPicture(Image image){ Messager->DrawShape();
//........
}
};
class MobileMessagerLite{
MobileMessagerBase* messager;
public: virtual void Login(string username, string password){ messager->Connect();
//........
}
virtual void SendMessage(string message){ messager->WriteText();
//........
}
virtual void SendPicture(Image image){ messager->DrawShape();
//........
}
};
我们发现除了红色部分不同,但是由Decorator模式中知道当一个变量的声明类型都是某个类的子类的时候,我们就该将他声明为某个类(基类),由于多态,我们可以使得他在未来(运行时)成为子类
(三)改进将子类转基类,实现在未来实现子类
class PCMessagerLite{
Messager* messager; //在未来是PCMessagerBase
public: virtual void Login(string username, string password){ Messager->Connect();
//........
}
virtual void SendMessage(string message){ Messager->WriteText();
//........
}
virtual void SendPicture(Image image){ Messager->DrawShape();
//........
}
};
class MobileMessagerLite{
Messager* messager;//在未来是MobileMessagerBase
public: virtual void Login(string username, string password){ messager->Connect();
//........
}
virtual void SendMessage(string message){ messager->WriteText();
//........
}
virtual void SendPicture(Image image){ messager->DrawShape();
//........
}
};
(四)发现两个类只是类名不同所以我们可以去重复
class MessagerLite{
Messager* messager;//在未来是MobileMessagerBase,和PcMessageBase
public: virtual void Login(string username, string password){ messager->Connect();
//........
}
virtual void SendMessage(string message){ messager->WriteText();
//........
}
virtual void SendPicture(Image image){ messager->DrawShape();
//........
}
};
class MessagerPerfect{ //一样的做法
Messager* Messager;//在未来是MobileMessagerBase,和PcMessageBase
public: virtual void Login(string username, string password){ Messager->PlaySound();
//********
Messager->Connect();
//........
}
virtual void SendMessage(string message){ Messager->PlaySound();
//********
PCMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){ Messager->PlaySound();
//********
Messager->DrawShape();
//........
}
};
(五)发现问题:接口规范出现问题(举一例)
class PCMessagerLite{
Messager* messager; //=new PCMessagerBase()
public: virtual void Login(string username, string password){ Messager->Connect();
//........
}
virtual void SendMessage(string message){ Messager->WriteText();
//........
}
virtual void SendPicture(Image image){ Messager->DrawShape();
//........
}
};
1.在红一处:我们未来会使用到new PCMessagerBase()来实现,但是我们发现 平台实现是继承纯虚基类
class PCMessagerBase : public Messager{ //只overwrite了部分纯虚函数,另外一部分并没有实现,所以还是抽象类无法实例化
public: virtual void PlaySound(){
//**********
}
virtual void DrawShape(){
//**********
}
virtual void WriteText(){
//**********
}
virtual void Connect(){
//**********
}
};
2.在红二处,我们并没有继承任何Messager基类,为何virtual使用,即使继承了,也是同上一样只实现了部分纯虚函数,无法进行实例化
(六)我们发现上面Messager将两大类功能写在一起是不合适的,我们应该进行拆分
class Messager{
public:
virtual void Login(string username, string password)=;
virtual void SendMessage(string message)=;
virtual void SendPicture(Image image)=;
virtual ~Messager(){}
}; class MessagerImp{ //平台实现时使用
public:
virtual void PlaySound()=;
virtual void DrawShape()=;
virtual void WriteText()=;
virtual void Connect()=; virtual ~MessagerImp(){}
};
下面是是修改基类
//平台实现
class PCMessagerImp : public MessagerImp{
public: virtual void PlaySound(){
//**********
}
virtual void DrawShape(){
//**********
}
virtual void WriteText(){
//**********
}
virtual void Connect(){
//**********
}
}; class MobileMessagerImp : public MessagerImp{
public: virtual void PlaySound(){
//==========
}
virtual void DrawShape(){
//==========
}
virtual void WriteText(){
//==========
}
virtual void Connect(){
//==========
}
};
//抽象业务
class MessagerLite:public Messager{
MessagerImp* messager; //转组合
public: virtual void Login(string username, string password){ messager->Connect();
//........
}
virtual void SendMessage(string message){ messager->WriteText();
//........
}
virtual void SendPicture(Image image){ messager->DrawShape();
//........
}
};
class MessagerPerfect:public Messager{ //一样的做法
MessagerImp* messager;
public: virtual void Login(string username, string password){ messager->PlaySound();
//********
messager->Connect();
//........
}
virtual void SendMessage(string message){ messager->PlaySound();
//********
messager->WriteText();
//........
}
virtual void SendPicture(Image image){ messager->PlaySound();
//********
messager->DrawShape();
//........
}
};
(七)同样的字段向上提,同Decorator
class Messager{ //是抽象业务的基类
protected:
MessagerImp* messagerImp;//...
public:
virtual void Login(string username, string password)=;
virtual void SendMessage(string message)=;
virtual void SendPicture(Image image)=; virtual ~Messager(){}
};
void Process(){
//运行时装配
MessagerImp* mImp=new PCMessagerImp();
Messager *m =new Messager(mImp);
}
此时类的数目是 1+1+n+m
但是运行时还是有组合的功能
(八)总结
class Messager{
public:
virtual void Login(string username, string password)=;
virtual void SendMessage(string message)=;
virtual void SendPicture(Image image)=; virtual void PlaySound()=;
virtual void DrawShape()=;
virtual void WriteText()=;
virtual void Connect()=; virtual ~Messager(){}
};
对比
class Messager{
protected:
MessagerImp* messagerImp;//...
public:
virtual void Login(string username, string password)=;
virtual void SendMessage(string message)=;
virtual void SendPicture(Image image)=; virtual ~Messager(){}
}; class MessagerImp{ //平台实现时使用
public:
virtual void PlaySound()=;
virtual void DrawShape()=;
virtual void WriteText()=;
virtual void Connect()=; virtual ~MessagerImp(){}
};
版本一中放了不同的函数
virtual void Login(string username, string password)=;
virtual void SendMessage(string message)=;
virtual void SendPicture(Image image)=;
virtual void PlaySound()=;
virtual void DrawShape()=;
virtual void WriteText()=;
virtual void Connect()=;
他们是不同的变化方向,一个方向是我们的平台实现,一个方向是业务抽象。
两个不同的变化方向,带动的行为的多态的实现也是应该往两个不同的方向走
四:模式定义
将抽象部分(业务功能)与实现部分(平台实现)分离,使它们都可以独立地变化。 ——《设计模式》GoF
五:类图(结构)
注意:稳定区域有一个多态指针在Messager中指向MessagerImp,这是和Decorator模式的一个区别
将抽象部分(业务功能)与实现部分(平台实现)分离,使它们都可以独立地变化。
六:要点总结
(一)Bridge模式使用“对象间的组合关系”解耦了抽象和实现之间固 有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。所谓 抽象和实现沿着各自纬度的变化,即“子类化”它们。
(二)Bridge模式有时候类似于多继承方案,但是多继承方案往往违背单一职责原则(即一个类只有一个变化的原因),复用性比较差。 Bridge模式是比多继承方案更好的解决方法。
一个单继承其他地方用组合的方式
(三)Bridge模式的应用一般在“两个非常强的变化维度”,有时一个类也有多于两个的变化维度,这时可以使用Bridge的扩展模式。
当有多个变化维度Bridge模式都给我们提供了一个方向,就是把属于其他变化维度的东西,把它合到一起,打包成一个基类,然后用一个指针指向她,若是有多个变化维度,就将用多个指针指向她
七:桥接模式和装饰模式的区别
(一)通过类图
(二)通过要点总结
(三)收集资料
1.定义:桥接模式就是应用合成/聚合复用原则的模式,而装饰模式是使用继承方式的模式。所以区别之一就出来了,一个使用的是继承方式,另一个使用的却是合成方式。
2.角度:装饰模式是动态地添加一些额外功能的模式,也就是说装饰模式是适应新需求而添加新功能,并且不影响其他对象的一种模式;而桥接模式是适应变化维度的一种模式,它在于将对象的各个维度的变化都独立开来,使一些变化不受其他因素变化的影响。
桥接模式是将各个维度的变化独立开来,扩展功能不多
class Messager{
protected:
MessagerImp* messagerImp;//...
public:
virtual void Login(string username, string password)=;
virtual void SendMessage(string message)=;
virtual void SendPicture(Image image)=; virtual ~Messager(){}
}; class MessagerImp{ //平台实现时使用
public:
virtual void PlaySound()=;
virtual void DrawShape()=;
virtual void WriteText()=;
virtual void Connect()=; virtual ~MessagerImp(){}
};
装饰模式,是为了更多适应新需求来扩展功能
但是最终都有减少类的冗余,提高了复用性
3.耦合:装饰模式中实现的是不同功能的子类进行封闭后独立的子类,但仍旧是紧耦合(因为是继承方式),而桥接模式中是将变化独立开,降低类之间的耦合度,尽最大可能实现松耦合(组合方式)。
4.结构:桥接模式中是指将抽象与实现分离或属性与基于属性的行为进行分离;而装饰者只是对基于属性的行为进行封闭成独立的类。
5. 行为:桥接中的行为是横向的行为,行为彼此之间无关联,具有非常强的变化维度;而装饰者模式中的行为具有可叠加性,其表现出来的结果是一个整体,一个各个行为组合后的一个结果
八:案例实现(不同颜色图形绘制)
(参考)设计模式读书笔记-----桥接模式
(一)平台实现和抽象业务的划分
class DrawShape
{
public:
//获取红色,绿色,蓝色
virtual void getRed() = ;
virtual void getGreen() = ;
virtual void getBlue() = ; //画圆,矩形,正方形
virtual void DrawCircle() = ;
virtual void DrawRect() = ;
virtual void DrawSquare() = ;
};
我们的业务是画图形,我们的平台可以是各个颜色,所以我们将上面一个类分为两个不同类分别代表抽象业务和平台实现
//平台实现基类
class ColorImp
{
public:
virtual void getPaint() = ;
virtual ~ColorImp(){}
}; //抽象业务基类
class DrawShape
{
protected:
ColorImp* color;
public:
DrawShape(ColorImp* clr) :color(clr){}
virtual void getShape();
virtual ~DrawShape(){}
};
(二)平台实现
class ColorImp //我们将获取颜色方法转换为基类,提供接口
{
public:
virtual void getPaint() = ;
virtual ~ColorImp(){}
}; class ColorRed :public ColorImp
{
public:
virtual void getPaint()
{
cout << "get red to paint" << endl;
}
}; class ColorGreen :public ColorImp
{
public:
virtual void getPaint()
{
cout << "get green to paint" << endl;
}
}; class ColorBlue :public ColorImp
{
public:
virtual void getPaint()
{
cout << "get blue to paint" << endl;
}
};
(三)抽象业务实现
class DrawShape
{
protected:
ColorImp* color;
public:
DrawShape(ColorImp* clr) :color(clr){}
virtual void getShape();
virtual ~DrawShape(){}
}; class DrawCircle :public DrawShape
{
public:
DrawCircle(ColorImp* clr) :DrawShape(clr){}
virtual void getShape()
{
color->getPaint();
cout << "use color to draw circle" << endl;
}
}; class DrawRect :public DrawShape
{
public:
DrawRect(ColorImp* clr) :DrawShape(clr){} virtual void getShape()
{
color->getPaint();
cout << "use color to draw rectangle" << endl;
}
}; class DrawSquare :public DrawShape
{
public:
DrawSquare(ColorImp* clr) :DrawShape(clr){} virtual void getShape()
{
color->getPaint();
cout << "use color to draw rectangle" << endl;
}
};
(四)测试代码
void main()
{
//获取平台
ColorImp* color = new ColorRed();
//设置业务
DrawShape* shape = new DrawCircle(color);
//测试结果
shape->getShape(); system("pause");
return;
}
#include <iostream>
using namespace std; class ColorImp
{
public:
virtual void getPaint() = ;
virtual ~ColorImp(){}
}; class DrawShape
{
protected:
ColorImp* color;
public:
DrawShape(ColorImp* clr) :color(clr){}
virtual void getShape() = ;
virtual ~DrawShape(){}
}; class ColorRed :public ColorImp
{
public:
virtual void getPaint()
{
cout << "get red to paint" << endl;
}
}; class ColorGreen :public ColorImp
{
public:
virtual void getPaint()
{
cout << "get green to paint" << endl;
}
}; class ColorBlue :public ColorImp
{
public:
virtual void getPaint()
{
cout << "get blue to paint" << endl;
}
}; class DrawCircle :public DrawShape
{
public:
DrawCircle(ColorImp* clr) :DrawShape(clr){}
virtual void getShape()
{
color->getPaint();
cout << "use color to draw circle" << endl;
}
}; class DrawRect :public DrawShape
{
public:
DrawRect(ColorImp* clr) :DrawShape(clr){} virtual void getShape()
{
color->getPaint();
cout << "use color to draw rectangle" << endl;
}
}; class DrawSquare :public DrawShape
{
public:
DrawSquare(ColorImp* clr) :DrawShape(clr){} virtual void getShape()
{
color->getPaint();
cout << "use color to draw rectangle" << endl;
}
}; void main()
{
//获取平台
ColorImp* color = new ColorRed();
//设置业务
DrawShape* shape = new DrawCircle(color);
//测试结果
shape->getShape(); system("pause");
return;
}
全部代码
个人觉得这种业务场景更加适合装饰器模式,因为这里平台扩展这些会更多些,但是用桥接也可以,还是需要大量经验才行....
设计模式---单一职责模式之桥模式(Bridge)的更多相关文章
- 设计模式---单一职责模式之装饰模式(Decorator)
前提:"单一职责"模式 在软件组件的设计中,如果责任划分的不清晰,使用继承,得到的结果往往是随着需求的变化,子类急剧膨胀,同时充斥着重复代码,这时候的关键是划清责任 典型模式(表现 ...
- 23种设计模式 - 单一职责(Decorator - Bridge)
其他设计模式 23种设计模式(C++) 每一种都有对应理解的相关代码示例 → Git原码 ⌨ 单一职责 在软件组件的设计中,如果责任划分的不清晰,使用继承得到的结果往往是随着需求的变化,子类急剧膨胀, ...
- 结构型模式(二) 桥接模式(Bridge)
一.动机(Motivation) 在很多游戏场景中,会有这样的情况:[装备]本身会有的自己固有的逻辑,比如枪支,会有型号的问题,同时现在很多的游戏又在不同的介质平台上运行和使用,这样就使得游戏的[装备 ...
- JavaScript高级---桥模式设计
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/stri ...
- 访问者模式(Visitor模式)
模式的定义与特点 访问者(Visitor)模式的定义:将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作,为数据结构中的每个元素提 ...
- C++设计模式 之 “单一职责”模式:Decorator、Bridge
part 1 “单一职责”模式 在软件组件的设计中,如果责任划分的不清晰,使用继承得到的结果往往是随着需求的变化,子类急剧膨胀,同时充斥着重复代码,这时候的关键是划清责任. 典型模式 Decorato ...
- 设计模式 - Bridge 桥模式
Bridge桥模式也属于"的单一职责"模式中的典型模式.问题描述:我们绘制图形时,图形可以有不同形状以及不同颜色,比如圆形可以是红的,绿的,方形可以是红的绿的,如果用代码来描绘这些 ...
- c++ 设计模式7 (Bridge 桥模式)
4.2 Bridge 桥模式 动机: 由于某些类型的固有的实现逻辑,使得它们具有两个变化的维度,乃至多个变化的维度. 代码示例: 实现一个Messager,含有基本功能PlaySound,Connec ...
- Java设计模式(6)桥模式(Bridge模式)
Bridge定义:将抽象和行为划分开来,各自独立,但能动态的结合. 为什么使用桥模式 通常,当一个抽象类或接口有多个具体实现(concrete subclass),这些concrete之间关系可能有以 ...
随机推荐
- <构建之法>第11、12章
第11章软件设计与实现 主要讲了典型的开发流程和开发阶段的一些管理方法 问题: 从spec道实现是代码的实现吗? 第12章 用户体验 主要讲了用户体验的各种角度和认识阻力登 问题: 用户的体验是设计前 ...
- mysql数据库忘记密码时如何修改
工具/原料 mysql数据库 cmd命令行 打开mysql.exe和mysqld.exe所在的文件夹,复制路径地址 打开cmd命令提示符,进入上一步mysql.exe所在的文件夹
- os模块+sys模块+random模块+shutil模块
os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径os.chdir("dirname") 改变当前脚本工作目录:相当于shell下cdos.curdir ...
- Maven Archetype简介以及搭建
为什么会写这篇文章,因为公司先在构建项目骨架都是用的 maven archetype ,身为一个上进的渣渣猿,自己还是有必要了解下这个东西的. Archetype介绍 Archetype 是一个 Ma ...
- linux ubuntu nethogs安装与介绍
安装nethogs: apt-get -y install ncurses* apt-get -y install libpcap-dev libncurses5-dev wget -c https: ...
- C# 8小特性
对于C# 8,有吸引了大多数注意力的重大特性,如默认接口方法和可空引用,也有许多小特性被考虑在内.本文将介绍几例可能加入C#未来版本的小特性. 新的赋值运算符:&&=和||= 从第一个 ...
- linux-shell系列8 netstat用法
1 查看TCP连接状态 netstat -n|awk '{print $6}'|sort|uniq -c|sort -rn netstat -n|awk '/^tcp/ {++S[$NF]};END{ ...
- Java8的flatMap如何处理有异常的函数
Java8的flatMap函数,作用是:如果有值,为其执行mapping函数返回Optional类型返回值,否则返回空Optional. 见到的映射函数往往都只有一句话,连大括号都不需要加的,如下: ...
- MT【12】三点坐标求面积
$L_1,L_2$是O发出的两条射线,C是一个常数,一条动直线$l$分别与$L_1,L_2$交于A,B两点.$S_{\Delta ABC}=C$,求A,B的中点D的轨迹方程.(2012北大自主招生) ...
- 【BZOJ4671】异或图(斯特林反演)
[BZOJ4671]异或图(斯特林反演) 题面 BZOJ Description 定义两个结点数相同的图 G1 与图 G2 的异或为一个新的图 G, 其中如果 (u, v) 在 G1 与 G2 中的出 ...