C + + Design Pattern -- Bridge pattern

Single responsibility mode:
 in the design of software components, if the division of responsibilities is not clear, the result of using inheritance is often that the subclass expands sharply with the change of requirements and is full of repeated code. At this time, the key is to clarify the responsibilities.
Typical mode
• Decorator
• Bridge

1. Bridge mode

Motivation
 due to the inherent implementation logic of some types, they have two changing dimensions and even multiple latitude changes.
 how to deal with this "multi-dimensional change"? How to use object-oriented technology to make types change easily in two or more directions without introducing additional complexity?

Code example

class Messager{
public:
    virtual void Login(string username, string password)=0;
    virtual void SendMessage(string message)=0;
    virtual void SendPicture(Image image)=0;

    virtual void PlaySound()=0; // Play sound
    virtual void DrawShape()=0; // Draw image
    virtual void WriteText()=0; // Write text
    virtual void Connect()=0; // Connect network
    
    virtual ~Messager(){}
};

//Platform implementation
class PCMessagerBase : public Messager{ //PC platform
public:
    
    virtual void PlaySound(){
        //**********
    }
    virtual void DrawShape(){
        //**********
    }
    virtual void WriteText(){
        //**********
    }
    virtual void Connect(){
        //**********
    }
};

class MobileMessagerBase : public Messager{ //Mobile platform
public:
    
    virtual void PlaySound(){
        //==========
    }
    virtual void DrawShape(){
        //==========
    }
    virtual void WriteText(){
        //==========
    }
    virtual void Connect(){
        //==========
    }
};

//Business abstraction
class PCMessagerLite : public PCMessagerBase { // PC platform Lite
public:
    
    virtual void Login(string username, string password){
        
        PCMessagerBase::Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        PCMessagerBase::WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        PCMessagerBase::DrawShape();
        //........
    }
};

class PCMessagerPerfect : public PCMessagerBase { // PC platform perfect
public:
    
    virtual void Login(string username, string password){
        
        PCMessagerBase::PlaySound(); // Play the sound first
        //********
        PCMessagerBase::Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        PCMessagerBase::PlaySound();
        //********
        PCMessagerBase::WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        PCMessagerBase::PlaySound();
        //********
        PCMessagerBase::DrawShape();
        //........
    }
};

class MobileMessagerLite : public MobileMessagerBase {
public:
    
    virtual void Login(string username, string password){
        
        MobileMessagerBase::Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        MobileMessagerBase::WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        MobileMessagerBase::DrawShape();
        //........
    }
};

class MobileMessagerPerfect : public MobileMessagerBase {
public:
    
    virtual void Login(string username, string password){
        
        MobileMessagerBase::PlaySound();
        //********
        MobileMessagerBase::Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        MobileMessagerBase::PlaySound();
        //********
        MobileMessagerBase::WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        MobileMessagerBase::PlaySound();
        //********
        MobileMessagerBase::DrawShape();
        //........
    }
};

void Process(){
        //Compile fashion accessories
        Messager *m = new MobileMessagerPerfect();
}

Messager function module includes PC platform and Mobile platform, and there are simplified version and perfect version on each platform. In PC platform and Mobile platform, the implementation of PlaySound(), DrawShape(), WriteText(), Connect() and other functions is different.
If there are m platforms and each platform has n versions, the number of classes will be 1 + n + m*n, which will be very large. And there is duplicate code in the class.

Convert inheritance relationship to composition

class PCMessagerLite { // PC platform Lite
	PCMessagerBase* message;
public:
    virtual void Login(string username, string password){        
        message->Connect();
        //........
    }
    // Other functions, omitted
}

class MobileMessagerLite{
	MobileMessagerBase* message;
	// Other functions, omitted
}

Further transformation

class PCMessagerLite {
	Messager* message; // new PCMessagerBase()
	//....
}

class MobileMessagerLite{
	Messager* message; // new MobileMessagerBase()
	//....
}

These two classes can be combined into one

class MessagerLite{
	Messager* message;
	//....
}

However, there is a problem. PCMessagerBase is an abstract class because it only override s some pure virtual functions of the base class Messager. In the Messager, Login, SendMessage, SendPicture and PlaySound, DrawShape, WriteText and Connect should be separated. These are different change directions. One is platform related and the other is business related.

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{ //Platform implementation related
public:
    virtual void PlaySound()=0;
    virtual void DrawShape()=0;
    virtual void WriteText()=0;
    virtual void Connect()=0;
    
    virtual MessagerImp(){}
};

//Platform implementation 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(){
        //==========
    }
};


//Business abstraction m
//Number of classes: 1+n+m
class MessagerLite :public Messager {  
	// MessagerImp* messagerImp;  There should have been this sentence, but it was mentioned in the parent class
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 {  
	// MessagerImp* messagerImp;  Lift up
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(){
    //Running fashion
    MessagerImp* mImp=new PCMessagerImp();
    Messager *m =new Messager(mImp);
}

Pattern definition
Separate the abstract part (business function) from the implementation part (platform implementation), so that they can change independently—— Design pattern GoF


Abstraction -- Abstract role
His main responsibility is to define the behavior of the role and save a reference to the implemented role, which is generally an abstract class.
Implementer -- implementing roles
It is an interface or abstract class that defines the behaviors and properties that a role must have.
Refined abstraction -- modify Abstract roles
He refers to the implementation role to modify the abstract role.
Concrete implementer -- concrete role
It implements methods and properties defined by interfaces or abstract classes.

Summary of key points
 Bridge mode uses * * "composite 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 mode is sometimes similar to multi inheritance schemes, but multi inheritance schemes often violate the principle of single responsibility (i.e. one class has only one reason for change), and the reusability is relatively poor. The Bridge pattern is a better solution than the multi inheritance scheme.
 Bridge mode is generally applied in "two very strong change dimensions". Sometimes a class also has more than two change dimensions. At this time, Bridge extension mode can be used

Keywords: C++ Design Pattern

Added by tweek on Sun, 20 Feb 2022 01:55:24 +0200