Bridge is a structural design pattern that aims to decouple an abstraction of its implementation, in a way that allows both to evolve in an independent way.

This pattern usage is recommended when dealing with classes have many different implementations and use inheritance to implement the abstraction. In those cases, the inheritance connects an implementation to the abstraction permanently, in a way that it’s hard to modify, increase and re-utilize the abstractions in an independent fashion.

To give an illustrated example, let’s pretend that we have a scenario where we want to create different types of bank accounts: CheckingAccount and SavingsAccount. We want our system to be flexible to the creation of new accounts types, so we create an abstract class called BankAccount and extend this class with CheckingAccount and SavingsAccount classes.

Great! Later, we want to give our account types their own personalized credit card type. We create BasicCreditCard, SilverCreditCard and GoldCreditCard classes. When binding those credit card to each bank account type, the problem gets clear:



The naive approach would be to create a combination for each account type, a solution which is costly and grows exponentially (imagine how much work if we add a new account type!). The code is also highly coupled, since different states and behaviors would be contained in a single class.

The Bridge pattern solves this issue by switching from inheritance to composition, and relocating all CreditCard classes to their own hierarchy. By doing that, we allow both contexts to evolve and change independently.



With that design in mind, let’s then create the CreditCard interface:



Now, we’ll create our types: Basic, Silver and Gold, all implementing the methods specified by the interface CreditCard.





Let’s create the abstraction BankAccount, the base class for our account types. This class will have an object of CreditCard, as well as a method to get the card information.



With all created, we can write our account types CheckingAccount and SavingsAccount:




To test our design, we’ll create a main class initializing each account with their respective credit card types.



… which outputs the following content:



In the end, Bridge pattern is a great tool to be used when we want to divide and refactor classes with a lot of variants, and also when we need to extend a class in independent dimensions. A great benefit in using this pattern is that it follows the open/closed principle (since we can add abstractions and implementations without impacting existing ones) and the single responsibility principle.

You can check the full implementation of this example here @ my Github: GracieleDamasceno/design-patterns!

References:

Bridge Pattern - Refactoring Guru

Design Patterns (2005), By Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides, Craig Larman