Bridge pattern

 

 Introduction:

Bridge is a structural design pattern which splits large class or set of closely related classes to two separate hierarchies; one for implementation and one for abstraction. These hierarchies are connected to each other via composition like bridge structure.

When to use, 

You have shape class which has two subclasses circle and square. Now you want to extend the hierarchy by adding colors red and yellow. Since we have two subclasses already, adding these two colors increases the number of subclasses by four like yellowSquare, yellowcircle, redSquare, and redcircle.
Adding new shapes and colors increases the number of subclasses exponentially. 

Picture: refactoring.guru







How to use, 

In the above example, number of subclasses increases when we try to add new color or shape. This problem happens in inheritance when we try to extend the shape class in two different dimensions by color and shape.

Picture: refactoring.guru










Bridge pattern solves this problem by extracting one of the dimension to separate class hierarchy , and original class contains the reference of new class hierarchy object (composition).
Bridge pattern solves this problem by switching inheritance to object composition.






Example,

How bridge pattern divides the monolithic app source code which manages both remote and devices.
Remote class acts as abstraction, device class acts as implementation. 

Bridge pattern divides the large class into two inheritance hierarchies. one for abstraction, another one for implementation. These two hierarchies are connected through the object composition like bridge structure. 

Implementation:

Sourcecode: https://github.com/krishnaKSA/design_patterns_cplusplus/blob/main/BridgePattern/BridgePattern.hpp

UML diagram:









Abstraction class:

//Abstraction class
    class remote
    {
        public:
        //implementation class object
        IDevice* deviceObj;
       
        //constructor
        remote(IDevice* device)
        {
            deviceObj = device;
        }
        //Set power status
        void power()
        {
            deviceObj->powerButton();
        }
        //Volume Up
        void volumeUp(uint8_t value)
        {
            uint8_t volume = deviceObj->getVolume();
            deviceObj->setVolume(volume + value);
        }
        //Volume Down
        void volumeDown(uint8_t value)
        {
            uint8_t volume = deviceObj->getVolume();
            deviceObj->setVolume(volume - value);
        }
        //Channel Up
        void channelUp(uint8_t value)
        {
            uint8_t channelNum = deviceObj->getChannelNumber();
            cout<<"channel num "<<channelNum<<endl;
            deviceObj->setChannelNumber(value + channelNum);
        }
        //Channel Down
        void channelDown(uint8_t value)
        {
            uint8_t channelNum = deviceObj->getChannelNumber();
            deviceObj->setChannelNumber(channelNum - value);
        }
    };

    //Derived class from abstraction class
    class advancedRemote : public remote
    {
        public:
        advancedRemote(IDevice* device):remote(device)
        {

        }
        void mute()
        {
            deviceObj->setVolume(0);
        }
    };

Implementation class:

//Implementation interface class.
    //This class provides the interfaces
    class IDevice
    {
        public:
        virtual bool powerButton() = 0;
        virtual void setVolume(uint8_t value) = 0;
        virtual uint8_t getVolume() = 0;
        virtual uint8_t getChannelNumber() = 0;
        virtual void setChannelNumber(uint8_t value) = 0;
    };

//Implementation class
    class TV : public IDevice
    {
        private:
        uint8_t channelNumber; //current channel number
        uint8_t volume; //current volume levels
        bool powerStatus; //current power status
        uint8_t MAX_VOLUME; //Max volume level
        uint8_t MAX_CHANNELS; //Maximum number of channels

        public:
        //constructor
        TV()
        {
            //set the default values
            channelNumber = 1; //default
            volume = 8; //default
            powerStatus = false; //powerOff
            MAX_VOLUME = 255;
            MAX_CHANNELS = 200;
        }
        //Set power ON/OFF
        bool powerButton()
        {
            powerStatus = !powerStatus;
            printf("Power status =%s \n",(powerStatus == true ? "ON" : "OFF"));
            return powerStatus;
        }
        //Set volume
        void setVolume(uint8_t value)
        {
            if(MAX_VOLUME != value)
            {
               volume = value;
            }
            if(0 == volume)
            {
                printf("Volume Muted \n");
            }
            else
            {
                printf("Volume level =%d\n",volume);
            }
        }
        //Get current volume
        uint8_t getVolume()
        {
            return volume;
        }
        //Set channel number
        void setChannelNumber(uint8_t value)
        {
            if(MAX_CHANNELS != value)
            {
                channelNumber = value;
            }
            printf("Channel number =%d\n", channelNumber);
        }
        //Get current channel number
        uint8_t getChannelNumber()
        {
            return channelNumber;
        }
    };

Client code:

    void testBridgePattern()
    {
        TV* tv = new TV();
        remote* abstractionObj = new remote(tv);

        //power On
        abstractionObj->power();
        abstractionObj->channelUp(1);
        abstractionObj->volumeDown(2);

        advancedRemote* advanced = new advancedRemote(tv);
        advanced->mute();
    }