C + + design pattern - bridging pattern

Bridging mode

Bridging is a structural design pattern, which can split business logic or a large class into different hierarchies, so that it can be developed independently.

A simple understanding is to separate the abstract part from the implementation part to realize decoupling.

scene

Realize the wechat and King glory APP of Honor30Pro and Mate40 mobile phones.

analysis

When encountering such scenarios, we usually abstract the mobile phone class, and then implement customized apps on different mobile phones (assuming that different mobile phone brands install the same APP, there will be some parameter differences).

If the mobile phone is abstracted, the following class diagram can be obtained:

Bridging mode

The above design abstracts the same part of each brand mobile phone, and the different part can be implemented in specific subclasses. Therefore, it is possible to realize different brand mobile phones with King glory and wechat (Honor, Mate40).

However, the above design exposes the following problems:

  • Every time a mobile phone is added, it is necessary to re implement a mobile phone subclass and various apps suitable for the current mobile phone.
  • Each mobile phone is highly coupled with the APP on its platform. For example, when the Hono30Pro class is modified, its subclasses King glory APP and wechat APP need to be modified accordingly.
  • This design will also cause the APP to bind to the mobile phone, so it is impossible to uninstall the specified APP from a mobile phone. Example: uninstall King glory on Mate40 mobile phone.

Abstract App

When the APP is abstracted, wechat and King glory that can be used for Mate40 and Honor30 Pro are obtained.

APP abstraction

This design has the same problems as the first design.

Abstract mobile phone and APP respectively

When we go back to analyze the scene, we find that there are two instances of the scene, mobile phone and APP, and the relationship is "has a", that is, aggregation. Then the mobile phone and APP can be abstracted separately to realize the aggregation relationship. Subclasses do not need to care about the relationship between them.

APP and mobile phone abstraction

As designed above, only CPhone class and CAPP class are coupled. In the actual implementation, CPhone and CAPP are dependent, and specific CPhone subclasses and CAPP are dependent and aggregated. The original highly coupled relationship is transformed into CPhone subclass coupled with CAPP abstract class.

This design has the following advantages:

  • Complete the decoupling of CPhone subclass and CApp subclass. Both can be modified independently without interference. More flexibility.
  • Easier to expand. When a new mobile phone or APP needs to be added, it can be completed without modifying the original code.

code

#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");

    // Customize King glory and wechat on 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;

    // Customize King glory and wechat on 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;
}

summary

  • The bridging pattern mainly separates abstraction from implementation. Complete the same partial coupling and the differential partial decoupling. Make the code more flexible, so that the modification of class implementation will not affect the effect of other code changes.
  • The client code can only interact with the high-level abstract part, and will not touch the details of the specific implementation.
  • Implement the opening and closing principle. The new abstract part and implementation part do not affect each other.
  • Implement the single principle. The abstract part focuses on dealing with high-level logic, and the implementation part deals with differentiated details.

Added by desithugg on Sat, 11 Dec 2021 07:41:07 +0200