[Design mode] Head First design mode - bridge mode C++ implementation

The biggest role of design patterns is to find isolation points between changes and stability, and then separate them to manage changes. Lock the change in a cage like a bunny, and let it jump around in the cage without jumping out and polluting your entire room.

design thinking

bridge mode. Separate the abstract part ( business functionality ) from the implementation part ( platform implementation ) so that they can both vary independently.

motivation

Certain types of inherent implementation logic make them have two dimensions of change, or even multiple latitudes of change.

The bridge pattern can cope with this "multi-dimensional change" and easily change along two or more directions without introducing additional complexity.

img

  • Abstract Implementor is a stable basic function (divided into multiple modules according to the dimension, and the part affected by the dimension is encapsulated independently)
  • RefinedAbstractionw is the first variable dimension (a member in Abstraction)
  • ConcreteImplementor is the second variable dimension (a member of Implementor)

Bridge uses the "composition relationship between objects" to decouple the inherent binding relationship between abstraction and implementation, so that abstraction and implementation can change along their respective dimensions. The so-called abstraction and implementation change along their respective latitudes, that is, "subclassing" them.

Bridge is sometimes similar to multiple inheritance schemes, but multiple inheritance schemes often violate the principle of single responsibility (that is, there is only one reason for a class to change), and the reusability is relatively poor. The Bridge pattern is a better solution than the multiple inheritance solution.

The application of Bridge is generally in "two very strong change dimensions". Sometimes a class also has more than two change dimensions. At this time, the extension mode of Bridge can be used.

Business scene

You plan to design a chat software Message, and plan to launch two versions: the PC version and the mobile version. Due to differences in platforms, there will be differences in the implementation of specific functions. And in the future, it is planned to launch two application versions on both platforms, one is the perfect version and the other is the lightweight Lite version. How would you design it?

If the application is inherited to implement, first design a base class Message (some things in this Message do not change due to platform differences, such as login and sending functions, but some are different, such as playing sound, typing text, etc.), Then, because there are two platforms, design two classes: PCMessage, MobileMessage to inherit this Message class, and because you want to launch two versions: perfect version and Lite lightweight version, so you need to design two classes to inherit PCMessage respectively , MobileMessage class, the final class diagram is roughly as follows:

insert image description here

It is not difficult to find that there are two dimensions of change in this case: different platforms and different versions are affecting your software. If your software needs to be registered on m platforms, and one software needs to be released in n versions, then if inheritance is adopted in the end, you have to design and implement 1+m+m*n classes. With the function iteration of your software, The iteration of versions and the increase of login platforms will eventually lead to an explosion of subcategories. This is a failed design.

The bridge pattern gives the answer to the question:

code example

class Messager{
protected:
     MessagerImp* messagerImp;//平台
public:
    virtual void Login(string username, string password)=0;
    virtual void SendMessage(string message)=0;
    virtual void SendPicture(Image image)=0;
    virtual ~Messager(){}
};
// 不同的变化方向(业务和平台),所以分为两个类
class MessagerImp{
public:
    virtual void PlaySound()=0;
    virtual void DrawShape()=0;
    virtual void WriteText()=0;
    virtual void Connect()=0;
    virtual MessagerImp(){}
};
//平台实现 n
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(){...}
};
//业务抽象 m
class MessagerLite :public Messager {
public:
    virtual void Login(string username, string password){
        messagerImp->Connect();
        //........
    }
    virtual void SendMessage(string message){
        messagerImp->WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        messagerImp->DrawShape();
        //........
    }
};
class MessagerPerfect  :public Messager { 
public:  
    virtual void Login(string username, string password){
        messagerImp->PlaySound();
        //********
        messagerImp->Connect();
        //........
    }
    virtual void SendMessage(string message){
        messagerImp->PlaySound();
        //********
        messagerImp->WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        messagerImp->PlaySound();
        //********
        messagerImp->DrawShape();
        //........
    }
};
void Process(){
    //运行时装配
    MessagerImp* mImp=new PCMessagerImp();
    Messager *m =new Messager(mImp);
}

Guess you like

Origin blog.csdn.net/weixin_43717839/article/details/132586233