The Bridge pattern is a structural pattern as defined by GOF (Gang-Of-Four)- to "decouple an abstraction from its implementation so that the two can vary independently" (GOF). To grasp the idea, I am going to spin up some C# code to demonstrate the concept and see the advantages that it brings along.
For this we're gonna be writing some software for rovers - maybe 200 or 300 rovers ready to go :). Ok, for this demo I am gonna only make 2 rovers (MarsRover, and MoonRover). But, same apply to the rest of the different rovers.
Here is the initial requirement: I need to be able to dispatch all the rovers and on the move method they should send out a message, collect some data and import it to sql database (in our case we're just using a string to show the data store type for simplicity).
First, let's see how we can do this without the bridge pattern. Let's examine the below code and see what is wrong with it.
We can see that we have a common Move method and the main concern is that we are specifying the data store type inside each rover. Let's assume we did this for 300 rovers and eventually we get a new requirement to try out the Oracle database instead. Now, we can see the maintenance nightmare because we would have to change all 300 rovers to use the Oracle data store. How about yet another requirement saying we just need to do this using the File System - this means doing it all over again and changing all 300 rovers. This is where the Bridge Pattern can help solve this issue.
Let's start by creating an abstract class and call it Rover:
Next we'll create the IDataCollector interface that has a single method called ImportData.
For simplicity I am including all classes in the same file to easily view on here. The below code shows the newly remodeled rovers:
I made them all override the Move method as well as abstracting the data store type through the use of IDataCollector interface. For our initial requirement we need a SQL data store, so let's create a class for that with a concrete implementation for importing data (we are just returning a string that says the type for simplicity). I am gonna also include classes for 2 other data store types (OracleDataCollector and FileSystemDataCollector):
Finally, let's take the code for s spin:
This will give us the following output:
If the requirements change, we do not have to change the rover code. For example if we just need to import data to the file system we can just replace the SQLDataCollector with the FileSystemDataCollector. Note that in real world scenario this can be done in configuration instead of instantiating a new collector inline.
In summary, let's take a look at a higher level picture of the Bridge Pattern and see where it all fit.
The abstrcation that we have created is the Rover and we have also refined that abstraction by creating MarsRover, and MoonRover. Our Implementor interface is IDataCollector and we have supplied multiple concrete implementations for that interface such as the SQLDataCollector,OracleDataCollection and so forth. Below is the UML Diagram for the rover scenario:
Cheers.