Bridge模式:
Bridge模式将抽象部分与它的实现部分分离,使它们都可以独立地变化。这并不是说,让抽象类与其派生类分离,因为这没有任何意义。实现指的是抽象类和它的派生类用来实现自己的对象。比如手机既可以按照品牌来分类,也可以按照功能来分类。再通俗点“将抽象部分与它的实现部分分离”就是现实系统可能有多角度分类,每一种分类都有可能变化,那么就把这种多角度分离出来让他们独立变化,减少它们之间的耦合。
这里引用《大话设计模式》中对于Bridge模式描述的手机游戏的例子:如果要实现一个N品牌的手机游戏,就提供一个此品牌的游戏类HandsetNGame。此时,如果再来一个M品牌的手机游戏,就提供一个HandsetMGame,并提取一个HandsetGame作为两个品牌手机游戏的基类。然后手机都需要通讯录功能,现在就有点麻烦了,父类应该是“手机品牌”,下面有“手机品牌M”和“手机品牌N”,每个品牌下各自有“通讯录”和“游戏”子类。
代码结构图如下:
1手机品牌
2手机品牌M
3手机品牌M通讯录
3手机品牌M游戏
2手机品牌N
3手机品牌N通讯录
3手机品牌N游戏
此时如果再来个MP3,就得在没个品牌下面增加一个MP3类。再来一个新品牌S,就得再增加“手机品牌S”和三个子类。如果再添加“输入法”、“拍照”…,再增加L品牌,X品牌,那类就呈爆炸性增长了。
或许可以换一种方式分类:
1手机软件
2通讯录
3手机品牌M通讯录
3手机品牌N通讯录
2游戏
3手机品牌M游戏
3手机品牌N游戏
但同样如果再来个新品牌S,再来个“输入法”,仍然得添加“手机品牌S”和“手机品牌S通讯录”,“手机品牌S游戏”,“手机品牌S输入法”。
上面两个单独的分类方式都没法解决类的膨胀。
先回顾下CARP(Composite/Aggregate Reuse Principle)原则:尽量使用组合/聚合,尽量不要使用类继承。
实际上,“游戏”、“通讯录”、“MP3”都是软件,不同的厂商生产不同的品牌。如果有个“手机品牌”抽象类,不同的品牌都继承于它;有个“手机软件”抽象类,不同的功能软件都继承于它。那么要增加新的品牌或者新的功能软件就不影响对方了。
即:
1手机品牌
2手机品牌M
2手机品牌N
1手机软件
2通讯录
2游戏
然后考虑下“手机品牌”和“手机软件”之间应该是什么关系呢?应该是手机品牌包含有手机软件,但软件并不是品牌的一部分,所以他们之间应该是聚合关系。
Bridge模式典型的结构图为:
分析到此,下面是Bridge模式的实现代码:
//Abstraction.h
#ifndef _ABSTRACTION_H_
#define _ABSTRACTION_H_
class HandsetSoft;
// 手机品牌
class HandsetBrand
{
public:
virtual ~HandsetBrand();
virtual void Operation() = 0;
protected:
HandsetBrand();
private:
};
// 手机品牌M
class HandsetBrandM : public HandsetBrand
{
public:
HandsetBrandM(HandsetSoft* imp);
~HandsetBrandM();
void Operation();
protected:
private:
HandsetSoft* _imp;
};
// 手机品牌N
class HandsetBrandN : public HandsetBrand
{
public:
HandsetBrandN(HandsetSoft* imp);
~HandsetBrandN();
void Operation();
protected:
private:
HandsetSoft* _imp;
};
#endif //~_ABSTRACTION_H_
//Abstraction.cpp
#include "Abstraction.h"
#include "AbstractionImp.h"
#include <iostream>
using namespace std;
HandsetBrand::HandsetBrand()
{
}
HandsetBrand::~HandsetBrand()
{
}
HandsetBrandM::HandsetBrandM(HandsetSoft* imp)
{
_imp = imp;
}
HandsetBrandM::~HandsetBrandM()
{
}
void HandsetBrandM::Operation()
{
_imp->Operation();
}
HandsetBrandN::HandsetBrandN(HandsetSoft* imp)
{
_imp = imp;
}
HandsetBrandN::~HandsetBrandN()
{
}
void HandsetBrandN::Operation()
{
_imp->Operation();
}
//AbstractionImp.h
#ifndef _ABSTRACTIONIMP_H_
#define _ABSTRACTIONIMP_H_
// 手机软件
class HandsetSoft
{
public:
virtual ~HandsetSoft();
virtual void Operation() = 0;
protected:
HandsetSoft();
private:
};
// 手机游戏
class HandsetSoftGame : public HandsetSoft
{
public:
HandsetSoftGame();
~HandsetSoftGame();
virtual void Operation();
protected:
private:
};
// 手机通讯录
class HandsetSoftAddressList : public HandsetSoft
{
public:
HandsetSoftAddressList();
~HandsetSoftAddressList();
virtual void Operation();
protected:
private:
};
#endif //~_ABSTRACTIONIMP_H_
//AbstractionImp.cpp
#include "AbstractionImp.h"
#include <iostream>
using namespace std;
HandsetSoft::HandsetSoft()
{
}
HandsetSoft::~HandsetSoft()
{
}
void HandsetSoft::Operation()
{
cout<<"HandsetSoft...操作手机软件..."<<endl;
}
HandsetSoftGame::HandsetSoftGame()
{
}
HandsetSoftGame::~HandsetSoftGame()
{
}
void HandsetSoftGame::Operation()
{
cout<<"HandsetSoftGame...操作手机游戏..."<<endl;
}
HandsetSoftAddressList::HandsetSoftAddressList()
{
}
HandsetSoftAddressList::~HandsetSoftAddressList()
{
}
void HandsetSoftAddressList::Operation()
{
cout<<"HandsetSoftAddressList...操作手机通讯录..."<<endl;
}
//main.cpp
#include "Abstraction.h"
#include "AbstractionImp.h"
#include <iostream>
using namespace std;
int main(int argc,char* argv[])
{
HandsetSoft* softg1 = new HandsetSoftGame();
HandsetBrand* brandm1 = new HandsetBrandM(softg1);
brandm1->Operation();
HandsetSoft* softa1 = new HandsetSoftAddressList();
HandsetBrand* brandm2 = new HandsetBrandM(softa1);
brandm2->Operation();
HandsetSoft* softg2 = new HandsetSoftGame();
HandsetBrand* brandn1 = new HandsetBrandN(softg2);
brandn1->Operation();
HandsetSoft* softa2 = new HandsetSoftAddressList();
HandsetBrand* brandn2 = new HandsetBrandN(softa2);
brandn2->Operation();
return 0;
}
与前面的Builder模式相比,Bridge和Builder都抽象出来一个基类,这个基类里面定义了共有的一些行为,形成接口函数;都聚合一个基类的指针,Builder因装配不同部分的过程是一致的,所以封装在构造函数中,Builder封装了不同的生成组成部分的方式,而Bridge封装了不同的实现方式。