前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >C++设计模式 - 桥接模式

C++设计模式 - 桥接模式

作者头像
开源519
发布于 2021-12-11 05:03:51
发布于 2021-12-11 05:03:51
26300
代码可运行
举报
文章被收录于专栏:开源519开源519
运行总次数:0
代码可运行

桥接模式

桥接是一种结构型设计模式,可将业务逻辑或一个大类拆分为不同的层次结构, 从而能独立地进行开发。

简单的理解,就是将抽象部分与实现部分分离,实现解耦。

场景

实现Honor30Pro与Mate40手机的微信与王者荣耀APP。

分析

遇到此类场景时,通常我们会抽象出手机类,然后在不同的手机上实现客制化的APP(假设不同的手机品牌安装同一款APP会有一些参数差异)。

如果将手机抽象,可以得到如下类图:

桥接模式

如上设计是将各个品牌手机相同部分抽象出来,差异性的部分可在具体的子类中实现。因此也就能够实现具备王者荣耀和微信的不同品牌手机(Honor、Mate40)。

但是上述设计又暴露出如下问题:

  • 每增加一款手机,就要重新实现一个手机子类以及适应当前手机的各个APP。
  • 每个手机与其平台上的APP高度耦合。例如,当Hono30Pro类发生修改时,其子类王者荣耀APP以及微信APP都需要随之修改。
  • 这种设计还会导致APP与手机绑定,从而无法实现从某个手机卸载指定的APP。例:在Mate40手机卸载王者荣耀。

将App抽象

将APP抽象时,得到可用于Mate40与Honor30 Pro的微信与王者荣耀。

APP抽象

此种设计与第一种设计存在相同的问题。

将手机与APP分别抽象

当回头再分析场景时,发现场景存在两个实例,手机和APP,且为“has a”的关系,即聚合。那么可将手机与APP分别抽象,实现聚合的关系,子类无需关心两者间的关系。

APP和手机抽象

如上设计,仅CPhone类与CAPP类有耦合关系。在实际的实现中,CPhone与CAPP为依赖关系,具体CPhone子类与CAPP为依赖聚合关系。将原先高度耦合的关系,转换为CPhone子类与CAPP抽象类耦合。

如此设计有以下优点:

  • 完成CPhone子类与CApp子类的解耦。两者都可以独立修改,互不干扰。灵活性更强。
  • 更容易扩展。当需要增加新的手机或APP时,能够在不修改原有的代码基础上完成。

代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <iostream>
#include <string>
#include <vector>

using namespace std;

class CApp
{
public:
    CApp()
    {

    }

    virtual ~CApp()
    {

    }
    virtual string GetName() = 0;
    virtual void ShowLogo() = 0;
    virtual void RunPlatform(string platform) = 0;
};

class CHonorOfKings : public CApp
{
public:
    CHonorOfKings(string logo)
    {
        mLogo = logo;
        mName = "HonorOfKings";
    }

    ~CHonorOfKings()
    {

    }

    string GetName()
    {
        return mName;
    }

    void ShowLogo()
    {
        cout << mLogo << " (" << mPlatform << ")" << endl;
    }

    void RunPlatform(string platform)
    {
        mPlatform = platform;
    }

private:
    string mName;
    string mLogo;
    string mPlatform;
};

class CWeChat : public CApp
{
public:
    CWeChat(string logo)
    {
        mLogo = logo;
        mName = "WeChat";
    }

    ~CWeChat()
    {

    }

    string GetName()
    {
        return mName;
    }

    void ShowLogo()
    {
        cout << mLogo << " (" << mPlatform << ")" << endl;
    }

    void RunPlatform(string platform)
    {
        mPlatform = platform;
    }

private:
    string mName;
    string mLogo;
    string mPlatform;
};

class CPhone
{
public:
    virtual ~CPhone()
    {
    
    }

    virtual void InstallApp(CApp *pApp) = 0;

    virtual void Uninstall(CApp *pApp) = 0;

    virtual void EnterApp(CApp *pApp) = 0;

    virtual void ShowAppList() = 0;
};

class CMate40: public CPhone
{
public:
    explicit CMate40(string name)
    {
        mName = name;
    }

    ~CMate40()
    {

    }

    void InstallApp(CApp *pApp)
    {
        pApp->RunPlatform(mName);
        mAppVec.push_back(pApp);
    }

    void Uninstall(CApp *pApp)
    {
        vector<CApp *>::iterator it;

        for (it = mAppVec.begin(); it != mAppVec.end(); ) {
            if ((*it)->GetName() == pApp->GetName()) {
                cout << "Uninstall " << (*it)->GetName() << " Success!" << endl;
                /* void removing the last element, coredump */
                it = mAppVec.erase(it);
            } else {
                it++;
            }
        }
    }

    void EnterApp(CApp *pApp)
    {
        pApp->ShowLogo();
    }

    void ShowAppList()
    {
        vector<CApp *>::iterator it;

        cout << "App List: ";
        for (it = mAppVec.begin(); it != mAppVec.end(); ) {
            cout << (*it)->GetName() << " ";
            it++;
        }
        cout << endl;
    }

private:
    string mName;
    vector <CApp*> mAppVec;
};

class CHonor30Pro : public CPhone
{
public:
    explicit CHonor30Pro(string name)
    {
        mName = name;
    }

    ~CHonor30Pro()
    {

    }

    void InstallApp(CApp *pApp)
    {
        pApp->RunPlatform(mName);
        mAppVec.push_back(pApp);
    }

    void Uninstall(CApp *pApp)
    {
        vector<CApp *>::iterator it;

        for (it = mAppVec.begin(); it != mAppVec.end(); ) {
            if ((*it)->GetName() == pApp->GetName()) {
                cout << "Uninstall " << (*it)->GetName() << " Success!" << endl;
                /* void removing the last element, coredump */
                it = mAppVec.erase(it);
            } else {
                it++;
            }
        }
    }

    void EnterApp(CApp *pApp)
    {
        pApp->ShowLogo();
    }

    void ShowAppList()
    {
        vector<CApp *>::iterator it;

        cout << "App List: ";
        for (it = mAppVec.begin(); it != mAppVec.end(); ) {
            cout << (*it)->GetName() << " ";
            it++;
        }
        cout << endl;
    }

private:
    string mName;
    vector <CApp*> mAppVec;
};

int main(int argc, char *argv[])
{
    CHonorOfKings theHonorOfKings("Timi");
    CWeChat theWeChat("Earth");

    // 定制 Honor 30 Pro 上的王者荣耀和微信
    CHonor30Pro thePhone("Honor 30 Pro");

    cout << "--- Honor 30 Pro ---" << endl;
    thePhone.InstallApp(&theHonorOfKings);
    thePhone.EnterApp(&theHonorOfKings);

    thePhone.InstallApp(&theWeChat);
    thePhone.EnterApp(&theWeChat);

    thePhone.ShowAppList();

    thePhone.Uninstall(&theWeChat);
    thePhone.ShowAppList();
    cout << endl;

    // 定制 Mate40 上的王者荣耀和微信
    CMate40 theMate40("Mate40");

    cout << "--- Mate40 ---" << endl;
    theMate40.InstallApp(&theHonorOfKings);
    theMate40.EnterApp(&theHonorOfKings);

    theMate40.InstallApp(&theWeChat);
    theMate40.EnterApp(&theWeChat);

    theMate40.ShowAppList();

    theMate40.Uninstall(&theWeChat);
    theMate40.ShowAppList();
    cout << endl;

    return 0;
}

总结

  • 桥接模式主要将抽象与实现分离。完成相同的部分耦合,差异化部分解耦。使代码灵活性更强,达到类实现部分的修改不会影响到其他代码改动的效果。
  • 客户端代码仅能够与高层抽象部分交互,不会接触到具体实现的详细细节。
  • 履行开闭原则。新增抽象部分与实现部分,两者互不影响。
  • 履行单一原则。抽象部分专注于处理高层逻辑,实现部分处理差异化细节。
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-12-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 开源519 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 桥接模式
    • 场景
    • 分析
    • 代码
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档