The Bridge Design Pattern is a Structural Design Pattern, which splits the abstraction from the implementation. In this article, we'll be covering the motivation and implementation of the Bridge Design Pattern in Python.
Design Patterns refer to a set of standardized practices or solutions to common architectural problems in software engineering.
Motivation Behind the Bridge Design Pattern
The Bridge Pattern prevents what's called the cartesian product complexity explosion.
The problem will be obvious going through an example. Suppose you're implementing an
Airplane. It can be a military or commercial airplane. Furthermore, it can be a passenger/soldier or cargo airplane.
One approach to implementing this is by having a
Here the cartesian product complexity is
2 x 2 = 4. This number isn't ground-breaking at this scale, but when you include more classes and variations, it can rise exponentially and it'll very quickly become unmanageable.
The Bridge Pattern is used, well, as a bridge between classes (
Airplane implementation) and their characteristics (is it a passenger or cargo plane). It favors composition over inheritance.
Using the pattern, you create one class for each of the types in different categories. For instance, in our example, we'd have a
MilitaryPlane as entities, with
PassengerCarrier as separate entities.
It might not look like we've done a lot since we've still got 4 classes, but imagine this on a scale. You can have
nPlane classes and only have
PassengerCarrier which you can apply to these planes.
An even better way would be to have parent classes -
Plane. For the
Carrier parent class, you can create two child classes:
Passenger. Similarly, for the
Plane parent class, two child classes:
Next, you will need a way to connect, or in other words, bridge
Plane subclasses. You can do so by passing one of these two classes as a parameter value in the constructor of the other class. By implementing the pattern, we'll be able to combine any of the subclasses.
Finally, let's see how we can implement the Bridge Design Pattern in Python.
Implementing the Bridge Design Pattern in Python
As I said earlier, we will create a parent class
Carrier with two abstract methods:
carry_passenger(). Next, we can create a child class
Cargo which inherits from the
Carrier class and implements the
To avoid the slippery slope of adding variations of classes, we'll define a
Carrier with two abstract methods -
Carrier class will additionally have two child classes -
Passenger which both inherit its abstract methods and implement them:
# Passenger & Cargo Carriers class Carrier: def carry_military(self, items): pass def carry_commercial(self, items): pass class Cargo(Carrier): def carry_military(self, items): print("The plane carries ", items," military cargo goods") def carry_commercial(self, items): print("The plane carries ", items," commercial cargo goods") class Passenger(Carrier): def carry_military(self, passengers): print("The plane carries ", passengers , " military passengers") def carry_commercial(self, passengers): print("The plane carries ", passengers , " commercial passengers")
In the same vein, we'll create a
Plane class with two abstract methods -
add_objects(), as well as two child classes -
Military. We'll be passing a
Carrier to the constructor of the
Plane class. This is the bridge.
If the plane is a
Commercial plane, it's
Passenger will return
carry_commercial(), and vice versa.
The number of passengers/goods will be stored in the
self.objects variable which is passed as a parameter to the
# Military & Commercial Planes class Plane: def __init__(self, Carrier): self.carrier = Carrier def display_description(self): pass def add_objects(self): pass class Commercial(Plane): def __init__(self, Carrier, objects): super().__init__(Carrier) self.objects = objects def display_description(self): self.carrier.carry_commercial(self.objects) def add_objects(self, new_objects): self.objects += new_objects class Military(Plane): def __init__(self, Carrier, objects): super().__init__(Carrier) self.objects = objects def display_description(self): self.carrier.carry_military(self.objects) def add_objects(self, new_objects): self.objects += new_objects
Our classes are primed and ready. Now is the time to create some objects and have them bridge between themselves through the previously mentioned constructor call.
Let's take a look at an example:
cargo = Cargo() passenger = Passenger() # Bridging Military and Cargo classes military1 = Military(cargo , 100) military1.display_description() military1.add_objects(25) military1.display_description()
Here, we've instantiated objects for the
Passenger classes. Then, in a constructor call to the
Military class, we've passed the
cargo instance. Since it's a military plane, the cargo is considered military cargo.
display_description() method will print out details regarding military cargo. Furthermore, we've added another
25 objects on top of this load:
The plane carries 100 military cargo goods The plane carries 125 military cargo goods
In the same vein, we can bridge the
Passenger classes as well:
cargo = Cargo() passenger = Passenger() # Bridging Military and Passenger classes military2 = Military(passenger , 250) military2.display_description() military2.add_objects(10) military2.display_description()
display_description() method results in the number of military passengers we're carrying:
The plane carries 250 military passengers The plane carries 260 military passengers
Similarly, we can bridge
# Bridging Commercial and Passenger commercial1 = Commercial(passenger , 400) commercial1.display_description() commercial1.add_objects(50) commercial1.display_description()
Which will result in:
The plane carries 400 commercial passengers The plane carries 450 commercial passengers
And finally, we can bridge the
# Bridging Commercial and Cargo commercial2 = Commercial(cargo, 150) commercial2.display_description() commercial2.add_objects(15) commercial2.display_description()
Which results in:
The plane carries 150 commercial cargo goods The plane carries 165 commercial cargo goods
The Bridge Design Pattern is a Structural Design Pattern, which splits the abstraction from the implementation. In this article, we've explored the motivation behind the Bridge Design Pattern and how it works.
Afterwards, we've implemented the pattern in Python, showcasing how the pattern works.