What
Bridge design pattern is a type of structural pattern which separates abstraction from its implementation. Due to separate hierarchy of abstraction and implementation it is very easy to adapt or modify both of them.
“Abstraction” means what the class shall do and “implementation” means how to do. Bridge pattern comes into picture when both the Abstraction and the Implementation are varying. Therefore, if there is a situation where we can’t freeze, what class will do and the ways how it will be done, the select bridge pattern.
Why
Lets us understand the need for Bridge design pattern by taking an example of a computer input & output device.
Here, the job of such input & output device application is, to take input from user and then show the output on the output device. As of now, our Computer application takes input from keyboard and shows output on the computer screen.
Example: Computer Input Output class
A traditional class having a input and output device may look like below code.
class ComputerInputOutput
{
string m_screen;
string m_Keyboard;
};
Suppose, now user wants to support more input devices such as:
- Mouse
- Trackball
- Touch.
Plus, also want to support more output devices for showing desired output:
- Touch Screen
- Curved Screen
- 3D screen
Inefficient method – without using Bridge Design Pattern
One way of doing this is, to keep adapting existing class ComputerInputOutput with all new types of devices.
Below is the updated class details:
class ComputerInpoutOutput
{
string m_screen;
string m_Keyboard;
string m_touchScreen;
string m_curvedScreen;
string m_mouse;
string m_trackball;
};
With above approach, the adaptation is not easy. This is because, whenever we support a new device, it shall impact lot of things. Firstly, we need to support a new device, and then we need to modify the ComputerInputOutput class. Due to such adaptations in the main class, there shall be impact on full application. Ultimately, we keep adapting client code again and again.
Due to the above issues, we need a pattern which supports such adaptations with minimal changes.
Bridge Design pattern is the best fit to solve such problems.
HOW
In order to update above application with Bridge Design pattern we need to follow below rules:
Create an “Abstraction” Class
First create an abstraction class, “ComputerInput” which select the desired input as per user requirements.
class ComputerInput
{
virtual void InputDisplay()=0;
};
Inherit from “Abstraction” Class
Inherit all valid and available inputs from ComputerInput class.
class keyboard: public ComputerInput
{
};
class Mouse: public ComputerInput
{
};
Create an “Implementation” Class
Create an implementation class, ComputerOutput which implements various output devices.
class ComputerOutput
{
public:
virtual void showOutput()=0;
};
Inherit from Implementation Class
The existing output devices should inherit from Implementation class.
class screen: public ComputerOutput
{
};
class touchScreen: public ComputerOutput
{
};
Create Bridge
Bridge abstraction with implementation by embedding implementation class inside abstraction class.
class ComputerInput
{
ComputerOutput *co;
}
Same Application with Bridge Design Pattern
#include<iostream> //main header
using namespace std; //for namespace
class ComputerOutput
{
public:
virtual void showOutput()=0;
};
class Screen:public ComputerOutput
{
public:
virtual void showOutput()
{
cout<<" Screen showing output";
}
};
class Touchscreen: public ComputerOutput
{
public:
virtual void showOutput()
{
cout<<"Touch Screen showing output"<<endl;
}
};
class Curvedscreen: public ComputerOutput
{
public:
virtual void showOutput()
{
cout<<"Curved Screen showing output"<<endl;
}
};
class ComputerInput
{
protected:
ComputerOutput *m_co;
public:
void setComputerOutput( ComputerOutput *co)
{
m_co =co;
}
virtual void InputDisplay()=0;
};
class Keyboard: public ComputerInput
{
public:
virtual void InputDisplay()
{
cout<<"Input Entered by keyboard"<<endl;
m_co->showOutput();
}
};
class Mouse: public ComputerInput
{
public:
virtual void InputDisplay()
{
cout<<"Input Entered by Mouse"<<endl;
m_co->showOutput();
}
};
int main()
{
ComputerOutput *co1 = new Screen;
ComputerInput *ci1 = new Keyboard;
ci1->setComputerOutput(co1);
ci1->InputDisplay();
ComputerOutput *co2 = new Curvedscreen;
ComputerInput *ci2 = new Mouse;
ci2->setComputerOutput(co2);
ci2->InputDisplay();
}
As seen above, now we have two hierarchies, one for abstraction and another for implementation. Therefore, if in future, a user wants to add more input or output devices, he can very easily add them. Basically, we need to only inherit from classes ComputerInput and ComputerOutput. There is no need to change the base class. There shall be very minimal changes required on the client side.
Pros and Cons of Bridge Design Pattern
Pros
- Firstly, it Separate Abstraction from its implementation so modification is very easy.
- Secondly, future adaptability is very easily accommodated with minimal changes in client code.
- Finally, it becomes possible to easily change both how and what of the application.
Cons
- Need to design abstraction and implementation very carefully otherwise design shall become very complex.