The Bridge Pattern is a Gang of Four (GoF) structural pattern. It uses two layers of abstraction called abstraction and implementor. This design pattern decouples the abstraction from its implementation by using class hierarchies. The abstraction has the reference of the implementor. The implementor is an interface or abstract class which defines the behavior of concrete implementation. The abstractions and implementation can be extended and bound dynamically. Refined abstraction extends abstraction and hides its specific implementation from the implementor.
We had to design an online ordering application which allowed users to place orders or request a demo for one or more than one product or a product suite. Since this use case had two layers of abstraction – (a) place order or request a demo and (b) order one or more than one product or a product suite, we decided to implement it using Bridge pattern. This would provide an additional advantage of being able to add any refined abstraction or concrete implementation during later stages of application enhancement. This design pattern also avoided tight coupling between order type and OrderableItem
type. The UML class diagram shown in Figure 1. demonstrates the design pattern implementation for this use case.
Figure 1. UML Class Diagram – Bridge pattern
The Order
is an abstraction. Its two concrete classes – DemoRequest and PurchaseOrder
– are refined abstraction. The OrderableItem
is an implementor with two implementing classes – Product
and ProductSuite
.
There is a slight variation in our design. In the traditional GoF pattern, there is only one reference of the implementor in the abstraction. However, since multiple product or product suites can be ordered in one order, we used a collection of implementor in the abstraction.
Degenerate Bridge
In our use case, there are more than one abstraction and implementors. However, there can be one-to-one mapping between abstraction and implementor which is referred as Degenerate Bridge pattern.
Advantages
- Abstraction is decoupled from implementation - Both are not tightly coupled which enables selecting appropriate implemention during runtime.
- Reduced code - If these abstraction layers are not used then it would require [number of refined abstraction classes X number of concrete implementation classes] number of classes to be implemented. Though this number is 2 X 2 = 4 in our use case, the count of classes would grow up dramatically with every addition in refined abstraction or concrete implementation, also leading to code duplication.
- Cleaner code - As mentioned in point 2, reduced code would look a lot more cleaner and easy to understand.
- Abstraction and Implementor could be modified without affecting the other layer - Any changes in abstraction or implementor layer won't affect the other layer. This would also reduce the chances of injecting errors in code.
- No impact on client code on modification in abstraction or implementation.
Drawback
The drawback of this design pattern is increased complexity.