Bridge Design Pattern falls under the structural design pattern category. This pattern focuses on a limitation in the concept of abstraction. In the context of Java, we use inheritance to develop the concept of abstraction. Several implementation deviations support to achieve the inheritance. However, this permanently binds the implementation to the abstraction limiting the flexibility. There can be situations when you want to modify or extend the abstraction as well as the implementations independently. Bridge pattern will help to resolve that limitation by decoupling the abstraction from its implementation.
This pattern is a fine example of the concept of ‘Prefer composition over inheritance’
GOF definition for bridge design pattern,
“Decouples an abstraction from its implementation so that the two can vary independently.”
What is Abstraction?
If we think of the point of Java language, abstraction can be defined by an interface or by an abstract class. It is a very narrow way to define the concept of abstraction. When thinking as an object-oriented concept, abstraction is just a representation or a generalization to more complex detail. Abstraction covers the details of concrete implementation of the whole thing.
Normally, when an abstraction requires more than one implementation inheritance is the mechanism, which use to accommodate that requirement. However, some scenarios require adding or modifying abstraction as well as the implementation independently without introducing any errors to the system.
Real Life Examples
Let’s assume a car and the remote control scenario. The car is the abstraction for this scenario. Toyota, Honda and Audi will be the implementations of the car abstraction. Each car will have set of remotes controls. If the remote control is the abstraction remote starter, remote door lock/open and remote alarm will be the implementations of the remote control. When there is one new addition to the car implementation like BMW. It also should have the 3 implementations of the remote control. Thus, abstractions and implementations can vary according to the requirement.
How Bridge Pattern Works?
In this pattern, usually, an abstract class represents the abstraction. That abstraction maintains a separate hierarchy. A separate hierarchy maintains the implementation of the abstract class. Likewise, pattern allows the class (abstraction) and what it does (Implementation) vary as required. The implantation consists of an abstraction point and several implementation criteria down the hierarchy.
Structure of the Bridge Pattern
Let’s clarify this using the abstraction and concrete implementation strategies. Assume you have two systems with abstract and concrete classes in each of the system. System X consists of ‘Abstract A’ and it’s concrete implementation ‘Concrete A’. Then, the System Y consists of ‘Abstract B’ and it’s concrete implementation ‘Concrete B’. Abstract A connects with the Abstract B by a ‘Has-A’ relationship. Abstract A maintains an instance of Abstract B within itself. This ‘Has-A’ relationship makes a bridge between the two systems. Hence, the pattern contains two layers of abstraction. Thus, the pattern was called as the bridge pattern.
Solution to the Problem
In an application, we should first identify the candidate component to develop an abstraction and as implementations. The abstraction and implementation are separated into two hierarchies and maintained independently.
Standard Technical Clarification for the Bridge Pattern
Figure 2 represents the UML diagram for the bridge design pattern. It depicts the two sets of abstractions, which vary independently.

Components of the Bridge Design Pattern
- Abstraction – This is one of the core components of the bridge pattern and it includes a reference to the implementor.
- Refined Abstraction – This extends the abstraction and hides the finer elements from implementor. That is this will not affect implementor, as well as these implementations, does not depend on any concrete implementors from the Implementor interface.
- Implementor – This is the interface to the lower level implementations. This does not need to directly relate to the abstraction. It only connects with a has-a relationship.
- ConcreteImplementor – This component implements the implementor interface by defining an implementation. Implementation details are hidden from the client.
.
Steps to implement the Pattern
- Identify what should vary independently
That is you have to derive and analyze classes based on orthogonal dimensions. They could be like front-end/back-end, domain/infrastructure, and interface/platform class hierarchies
- Identify the ‘Implementor’ interface by analyzing the varying feature for the candidate classes
- Identify one class category as the ‘Abstraction’ and build the abstract class and include an instance of an ‘Implementor’ with the abstract class
- Then extend the abstract class to generate different implementations to cater your varying requirements
- Build the client program to obtain your need
- You can add more concrete classes for both ‘abstraction’ and ‘implementor’ as required and expand the system
Code Example
Let us take a simple example to clarify this pattern. Assume one digital artist needs to create shapes with different colours. He is developing a program to achieve this goal. Initially, there will be few options. However, depending on the customer, requirements there will be different types shapes and variety of colours can be accommodated to produce best outcomes. Thus, the artist will have to add different shapes to the ‘Shape’ category as well as incorporate many colours to the ‘Color’ category in the future.
Before going further, let us see what happens without the bridge pattern.
Without the Bridge Pattern
You will have to create long and complex subclasses for each shape with difficult naming patterns.
With the Bridge Pattern
Two class hierarchies will allow more flexibility between two class hierarchies.
Let us put this scenario to the Java programming context.
Components of the Program
- AbstractShape : Represents the abstract class/interface of the set of concrete shape implementations
- RefinedShapeCircle : Circle is one extension of the ‘Shape’ abstraction
- RefinedShapeTriangle : Triangle is another example of the ‘Shape’ abstraction
- ColorImplementor : This is the abstraction for the ‘Color’ category and part of implementation for the ‘Shape’ category.
- ConcreteColorRed : Red color extension of the ‘Color’ abstraction
- ConcreteColorGreen : Green color extension of the ‘Color’ abstraction
Java Code Samples
ColorImplementor.java
1 2 3 4 5 |
public interface ColorImplementor { public void applyColor(); } |
AbstractShape.java
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public abstract class AbstractShape { // Creating the implementor instance (Composition) protected ColorImplementor color; // constructor with implementor as input argument public AbstractShape(ColorImplementor c) { this.color = c; } //Abstract method related to filling the color to the object abstract public void applyShapeColor(); } |
RefinedShapeCircle.java
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class RefinedShapeCircle extends AbstractShape { public RefinedShapeCircle(ColorImplementor c) { super(c); } @Override public void applyShapeColor() { System.out.print("Circle color applying - "); color.applyColor(); } } |
RefinedShapeTriangle.java
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class RefinedShapeTriangle extends AbstractShape { public RefinedShapeTriangle(ColorImplementor c) { super(c); } @Override public void applyShapeColor() { System.out.print("Triangle color applying - "); color.applyColor(); } } |
ConcreteColorRed.java
1 2 3 4 5 6 7 8 |
public class ConcreteColorRed implements ColorImplementor{ @Override public void applyColor() { System.out.println("Applying Red...."); } } |
RefinedShapeCircle.java
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class RefinedShapeCircle extends AbstractShape { public RefinedShapeCircle(ColorImplementor c) { super(c); } @Override public void applyShapeColor() { System.out.print("Circle color applying - "); color.applyColor(); } } |
ShapeColorTester.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
public class ShapeColorTester { public static void main(String[] args) { // Creating the Triangle instance and apply red color System.out.println("Appying Red Color to the Triangle"); AbstractShape triagleRed = new RefinedShapeTriangle(new ConcreteColorRed()); triagleRed.applyShapeColor(); // Creating the Triangle instance and apply green color System.out.println("Appying Green Color to the Triangle"); AbstractShape triagleGreen = new RefinedShapeTriangle(new ConcreteColorGreen()); triagleGreen.applyShapeColor(); // Creating the Circle instance and apply red color System.out.println("Appying Red Color to the Circle"); AbstractShape circleRed = new RefinedShapeCircle(new ConcreteColorRed()); circleRed.applyShapeColor(); // Creating the Circle instance and apply green colour System.out.println("Applying Green Color to the Circle"); AbstractShape circleGreen = new RefinedShapeCircle(new ConcreteColorGreen()); circleGreen.applyShapeColor(); } } |
When to use the Bridge Pattern
- When there is a need to void the permanent binding or tight coupling between an abstraction and implementation. In this case, implementation may select or switch at run-time
- When there is a need for extending the abstraction and the composite implementation separately by subclasses.
- When the change in extended implementations should not impact the client
- When there is a hierarchical propagation of several categories of classes in the system
Advantageous of Bridge Design Pattern
- Bridge patterns allows independent variation between two abstract and implementor systems
- It avoids the client code binding to a certain implementation
- Abstraction and implementation can be clearly separated allowing easy future extension
- Provides a good solution for cross-platform development
- Well suited for testing with stubs in initial development cycle
Drawbacks of Bridge Design Pattern
- This pattern may cause complexity if the number of extensible components increased
- Possible performance issues due to unclear messaging
Difference between Bridge & Adapter Pattern
- Adapter is used to eliminate the incompatibility of an already defined and existing two system while bridge pattern used to address any difficulties prior to developing the systems
You can find the code used in this tutorial on github bridge design pattern