您现在的位置是:首页 >技术交流 >设计模式之桥接模式网站首页技术交流
设计模式之桥接模式
之前有时间的时候总是会读一下设计模式,但是总是觉得似懂非懂,当时记住了,没多久又忘记了,近来看了李建忠讲的设计模式,感觉有所收获。
首先要理解这个模式要解决什么问题:
在软件开发设计中,由于类封装的不合理,责任划分的不明确,使继承得到的具体子类数量急剧膨胀,也同时充斥着大量的重复代码。
桥接模式的主要用途就是 将抽象维度与实现维度去分离成两条线,再将两条线上的类进行组合,动态的实现所需要的功能。
接下来时代码演示,让我们更好的理解这个模式的作用。
假设现在有如下需求:
需要设计消息发送模块,模块又 登录,发送文字,发送图片接口
模块有精简版、标准版(执行具体动作前播放提示音)、完美版(执行具体动作前、后播放提示音)
这时候可能我们大脑中已经设计类的抽象结构了,可能如下
具体代码:
class Messager {
public:
Messager(){};
virtual ~Messager(){};
virtual int Login(string user_name, string pwd) = 0;
virtual int SendText(string strText) = 0;
virtual int SendImage(string strPath) = 0;
virtual void PlaySound() = 0;
virtual void DrawPicture() = 0;
virtual void Connect() = 0;
virtual void WriteText() = 0;
};
class PCMessagerBase : public Messager {
public:
PCMessagerBase(){};
virtual ~PCMessagerBase(){};
public:
virtual int Login(string user_name, string pwd){
return 0;
};
virtual int SendText(string strText){ return 0; };
virtual int SendImage(string strPath) { return 0; };
public:
virtual void PlaySound(){ cout << "PC PlaySound" << endl; };
virtual void DrawPicture(){ cout << "PC DrawPicture" << endl; };
virtual void Connect(){ cout << "PC Connect" << endl; };
virtual void WriteText(){ cout << "PC WriteText" << endl; };
};
class MobileMessagerBase : public Messager {
public:
MobileMessagerBase(){};
virtual ~MobileMessagerBase(){};
public:
virtual int Login(string user_name, string pwd){
return 0;
};
virtual int SendText(string strText){ return 0; };
virtual int SendImage(string strPath) { return 0; };
public:
virtual void PlaySound(){ cout << "Mobile PlaySound" << endl; };
virtual void DrawPicture(){ cout << "Mobile DrawPicture" << endl; };
virtual void Connect(){ cout << "Mobile Connect" << endl; };
virtual void WriteText(){ cout << "Mobile WriteText" << endl; };
};
class PCMessagerLite : public PCMessagerBase {
public:
PCMessagerLite(){};
virtual ~PCMessagerLite(){};
public:
virtual int Login(string user_name, string pwd){
PCMessagerBase::Connect();
return 0;
};
virtual int SendText(string strText){
PCMessagerBase::WriteText();
return 0;
};
virtual int SendImage(string strPath) {
PCMessagerBase::DrawPicture();
return 0;
};
public:
virtual void PlaySound(){};
virtual void DrawPicture(){};
virtual void Connect(){};
virtual void WriteText(){};
};
class PCMessagerPerfect : public PCMessagerBase {
public:
PCMessagerPerfect(){};
virtual ~PCMessagerPerfect(){};
public:
virtual int Login(string user_name, string pwd){
PCMessagerBase::PlaySound();
PCMessagerBase::Connect();
PCMessagerBase::PlaySound();
return 0;
};
virtual int SendText(string strText){
PCMessagerBase::PlaySound();
PCMessagerBase::WriteText();
PCMessagerBase::PlaySound();
return 0;
};
virtual int SendImage(string strPath) {
PCMessagerBase::PlaySound();
PCMessagerBase::DrawPicture();
PCMessagerBase::PlaySound();
return 0;
};
public:
virtual void PlaySound(){};
virtual void DrawPicture(){};
virtual void Connect(){};
virtual void WriteText(){};
};
class PCMessagerStandard : public PCMessagerBase {
public:
PCMessagerStandard(){};
virtual ~PCMessagerStandard(){};
public:
virtual int Login(string user_name, string pwd){
PCMessagerBase::PlaySound();
PCMessagerBase::Connect();
return 0;
};
virtual int SendText(string strText){
PCMessagerBase::PlaySound();
PCMessagerBase::WriteText();
return 0;
};
virtual int SendImage(string strPath) {
PCMessagerBase::PlaySound();
PCMessagerBase::DrawPicture();
return 0;
};
public:
virtual void PlaySound(){};
virtual void DrawPicture(){};
virtual void Connect(){};
virtual void WriteText(){};
};
class MobileMessagerLite : public MobileMessagerBase {
public:
MobileMessagerLite(){};
virtual ~MobileMessagerLite(){};
public:
virtual int Login(string user_name, string pwd){
MobileMessagerBase::Connect();
return 0;
};
virtual int SendText(string strText){
MobileMessagerBase::WriteText();
return 0;
};
virtual int SendImage(string strPath) {
MobileMessagerBase::DrawPicture();
return 0;
};
public:
virtual void PlaySound(){};
virtual void DrawPicture(){};
virtual void Connect(){};
virtual void WriteText(){};
};
class MobileMessagerPerfect : public MobileMessagerBase {
public:
MobileMessagerPerfect(){};
virtual ~MobileMessagerPerfect(){};
public:
virtual int Login(string user_name, string pwd){
MobileMessagerBase::PlaySound();
MobileMessagerBase::Connect();
MobileMessagerBase::PlaySound();
return 0;
};
virtual int SendText(string strText){
MobileMessagerBase::PlaySound();
MobileMessagerBase::WriteText();
MobileMessagerBase::PlaySound();
return 0;
};
virtual int SendImage(string strPath) {
MobileMessagerBase::PlaySound();
MobileMessagerBase::DrawPicture();
MobileMessagerBase::PlaySound();
return 0;
};
public:
virtual void PlaySound(){};
virtual void DrawPicture(){};
virtual void Connect(){};
virtual void WriteText(){};
};
class MobileMessagerStandard : public MobileMessagerBase {
public:
MobileMessagerStandard(){};
virtual ~MobileMessagerStandard(){};
public:
virtual int Login(string user_name, string pwd){
MobileMessagerBase::PlaySound();
MobileMessagerBase::Connect();
return 0;
};
virtual int SendText(string strText){
MobileMessagerBase::PlaySound();
MobileMessagerBase::WriteText();
return 0;
};
virtual int SendImage(string strPath) {
MobileMessagerBase::PlaySound();
MobileMessagerBase::DrawPicture();
return 0;
};
public:
virtual void PlaySound(){};
virtual void DrawPicture(){};
virtual void Connect(){};
virtual void WriteText(){};
};
这时候我们会发现,如果我们再增加多一个平台的支持,就要增加4个类,而且此时不同平台的精简版、标准版,完美版,代码看起来非常的类似,重复。
桥接模式推荐我们将不同维度的变化去分离,然后让他们以动态组合的方式去实现功能
上面的代码中,我们会发现,Messager这个类有两个变为的维度,一个是平台实现(pc,mobile)另一个是业务抽象维度(轻量版、标准版、完美版),接下来我们将类按照这两个变换的维度去拆分成两个类,分别是 Messager, 以及它的平台实现MessagetImp
结构如下图所示:
具体代码如下:
namespace GOF_BRIDGE {
class MessagerImp {
public:
MessagerImp(){};
virtual ~MessagerImp(){};
virtual void PlaySound() = 0;
virtual void DrawPicture() = 0;
virtual void Connect() = 0;
virtual void WriteText() = 0;
};
class Messager {
public:
Messager(MessagerImp* pMI){ m_pMI = pMI; };
virtual ~Messager(){};
virtual int Login(string user_name, string pwd) = 0;
virtual int SendText(string strText) = 0;
virtual int SendImage(string strPath) = 0;
protected:
MessagerImp* m_pMI;
};
class MobileMessagerImp : public MessagerImp {
public:
MobileMessagerImp(){};
virtual ~MobileMessagerImp(){};
public:
virtual void PlaySound(){ cout << "Mobile PlaySound" << endl; };
virtual void DrawPicture(){ cout << "Mobile DrawPicture" << endl; };
virtual void Connect(){ cout << "Mobile Connect" << endl; };
virtual void WriteText(){ cout << "Mobile WriteText" << endl; };
};
class PCMessagerImp : public MessagerImp {
public:
PCMessagerImp(){};
virtual ~PCMessagerImp(){};
public:
virtual void PlaySound(){ cout << "PC PlaySound" << endl; };
virtual void DrawPicture(){ cout << "PC DrawPicture" << endl; };
virtual void Connect(){ cout << "PC Connect" << endl; };
virtual void WriteText(){ cout << "PC WriteText" << endl; };
};
class MessagerLite : public Messager {
public:
MessagerLite(MessagerImp* pMI) : Messager(pMI){};
virtual ~MessagerLite(){};
public:
virtual int Login(string user_name, string pwd){
m_pMI->Connect();
return 0;
};
virtual int SendText(string strText){
m_pMI->WriteText();
return 0;
};
virtual int SendImage(string strPath) {
m_pMI->DrawPicture();
return 0;
};
public:
virtual void PlaySound(){};
virtual void DrawPicture(){};
virtual void Connect(){};
virtual void WriteText(){};
};
class MessagerPerfect : public Messager {
public:
MessagerPerfect(MessagerImp* pMI) : Messager(pMI){};
virtual ~MessagerPerfect(){};
public:
virtual int Login(string user_name, string pwd){
m_pMI->PlaySound();
m_pMI->Connect();
m_pMI->PlaySound();
return 0;
};
virtual int SendText(string strText){
m_pMI->PlaySound();
m_pMI->WriteText();
m_pMI->PlaySound();
return 0;
};
virtual int SendImage(string strPath) {
m_pMI->PlaySound();
m_pMI->DrawPicture();
m_pMI->PlaySound();
return 0;
};
public:
virtual void PlaySound(){};
virtual void DrawPicture(){};
virtual void Connect(){};
virtual void WriteText(){};
};
class MessagerStandard : public Messager {
public:
MessagerStandard(MessagerImp* pMI) : Messager(pMI){};
virtual ~MessagerStandard(){};
public:
virtual int Login(string user_name, string pwd){
m_pMI->PlaySound();
m_pMI->Connect();
return 0;
};
virtual int SendText(string strText){
m_pMI->PlaySound();
m_pMI->WriteText();
return 0;
};
virtual int SendImage(string strPath) {
m_pMI->PlaySound();
m_pMI->DrawPicture();
return 0;
};
public:
virtual void PlaySound(){};
virtual void DrawPicture(){};
virtual void Connect(){};
virtual void WriteText(){};
};
}
int _tmain(int argc, _TCHAR* argv[])
{
Messager* pM = new PCMessagerPerfect;
pM->Login("", "");
GOF_BRIDGE::MessagerImp* pImp = new GOF_BRIDGE::PCMessagerImp();
GOF_BRIDGE::Messager* pM1 = new GOF_BRIDGE::MessagerPerfect(pImp);
pM1->Login("", "");
system("pause");
return 0;
}
此时 我们用7个类解决了 一开始需要9个类来解决的问题,更重要的时如果我们再增加多一个平台的支持,比如再增加一个Arm平台,就只要增加1个类(ArmMessagerImp),对比使用设计模式之前的代码需要增加4个类(ArmMessagerBase、ArmMessagerLite、ArmMessagerStandard、ArmMessagerPerfect)来说,无论是开发效率以及未来的可维护性来说,都是提高了很多~
看到了使用桥接模式带来的具体效果,感觉多这个模式的理解也加深,记忆也更加深刻了,你说对不对?
再对照一下桥接模式的结构图
是不是一下子就理解了呢?