When your project starts to get larger and more complicated, every little change in some of its parts can affect other parts. This may prevent you from developing new features for your project so as to avoid all the mess that can happen. One of the few fixes for such a problem is presented in the form of a structural design pattern called Bridge.
What is bridge?
Bridge is a structural design pattern that works on separation of abstraction and implementation to make their independent development possible. That might sound a bit confusing, so let's start from the basics. What are abstraction and implementation?
Abstraction — A layer that represents the working process to the users and allows them to interact with the system. This layer isn't doing any real work, as it only delegates it to the implementation.
Implementation — A layer that defines and represents all the actual working processes within your system. Usually, users don't directly interact with it.
In real applications, abstraction may be represented by a graphical interface, operated by users, and implementation is an interface that transfers user commands to the system. So it's fairly simple to understand. But why should we separate them using the bridge pattern?
Bridge applicability
Using separation of abstraction and implementation, you can maintain two independent development directions. This will allow you to simultaneously work on a UI avoiding interference to your API-related parts and vice versa.
For example, let's look at a TV and its remote controller. In this case, the remote controller will represent the abstraction layer and the TV will represent the implementation layer:
TV is a device that contains all functionality and logic that allows a viewer to just watch it without low-level interaction with its parts. This easy form of interaction is provided by remote.
Remote represents a high-level controller which allows viewers to make basic operations with TV, like turning it on/off, changing channels, etc.
This is the basic form of abstraction and implementation separation. It will allow us to develop our remote independently from the TV. As a matter of fact, we can create several types of remotes and TVs which could be interchangeable. Some types will provide more functions than others.
Bridge in pseudocode
Now let's try to depict our TV with a remote in pseudocode. First, we will have to describe our TVs. They will be created through the TV interface:
interface TV is
method isEnabled()
method enable()
method disable()This method will be used for each new implementation class. Now we'll make two implementation classes called SmartTV and SimpleTV:
class SmartTV implements TV is
...
class SimpleTV implements TV is
...Next, we'll define our abstraction class, Remote. In this class, we will include the TV field. This way, abstraction will delegate all the work to implementation referencing that particular field. It will be a simple remote which can turn on and turn off our TV:
class Remote is
field tv: TV
constructor Remote(tv: TV) is
this.tv = tv
method power() is
if (tv.isEnabled()) then
tv.disable()
else
tv.enable()So now if we want to access SmartTV or SimpleTV methods, we can do it from our Remote:
SmartTV = new SmartTV()
remoteSmart = new Remote(SmartTV)
remoteSmart.power()
SimpleTV = new SimpleTV()
remoteSimple = new Remote(SimpleTV)
remoteSimple.power()This structure will allow you to create several variations of objects which will be independent of each other.
Conclusion
Bridge pattern is useful in a situation when you want to separately develop a representation of your object and all of its inner logic. It will allow you to control the appearance of an application and all the actual application work will go untouched. This will also make your code more flexible, allowing you to modify it while working with the same common UI.