Introduction
The bridge design pattern in Java works on the concept of decoupling the abstraction from its implementation to make both independents. In other words, it separates the abstraction from its implementation. This is done by introducing an interface as a Bridge between the Abstraction and the Implementation.
The bridge pattern almost behaves like the Adapter Design pattern, where Adapter works with the legacy code and bridge works with the new code. Both are structural design patterns and almost share the same behaviors.
1. When to use the Bridge Design Pattern?
- The situation where we do not want the tight binding between the abstraction and its implementation. This means that when you need the run-time binding of the implementation.
- When we want to have more subclasses which may extend the Abstraction and its implementation.
- The changes in the implementation of the abstraction should not have an impact on the client-side. This means that there is no need to recompile the code if changes have been made to the implementation.
- There is a need for Sharing one object among multiple clients.
- We need to hide the implementation of the abstractions for the client.
2. Working principle of Bridge pattern.
As per above, we know that bridge pattern works by defining an Interface between the abstraction and it achieves the run-time binding of the implementation.
Look at the diagram below which is showing the exact working principle of this pattern.
In the above diagram, the Abstraction
is an interface, which can be refined into the more specific implementation of the above interface. Then we have the implementor which is the hierarchy of our abstract classes. The abstract classes will then be defined into a more concrete implementation which will utilize composition of the various pieces of our bridge pattern to define those concrete implementation.
3. Use-case of Bridge pattern.
Let us say a manufacturer company manufactures different kinds of electronic items such as tv and mobiles. Both of the items can be of different kinds of models and brands. To implement the new models in the existing system without a design pattern may require the code changes in the previous project as well.
To overcome this, we can implement such a design pattern that is open to adapt any type of new model of items introduced to the production.
Let us look into the implementation of the above use-case.
3.1. Code Implementation
Below Abstract class ElectronicItem.java
having the parameterized constructors, and one method produce()
will be implemented by the concrete classes to produce the different types of items.
package javadesignpatterns.structural.bridge; public abstract class ElectronicItem { protected Factory factory1; protected Factory factory2; protected ElectronicItem(Factory factory1, Factory factory2) { this.factory1 = factory1; this.factory2 = factory2; } abstract public void produce(); }
The class below Tv.java
is the implementation class of one of the items TV. This is basically a Refine abstraction 1 in bridge pattern which is extending the above abstract class. This class is having the parameterized constructor in which we are Factory object. Here we are also overriding the abstract method to produce the item Tv.
package javadesignpatterns.structural.bridge; public class Tv extends ElectronicItem { public Tv(Factory factory1, Factory factory2) { super(factory1, factory2); } @Override public void produce() { System.out.print("Tv "); factory1.production(); factory2.production(); } }
The class below Mobile.java
is the implementation class of one of the items Mobile. This is basically a Refine abstraction 2 of the bridge pattern, which is extending the above abstract class. This class is having the parameterized constructor in which we are Factory object. Here we are also overriding the abstract method to produce the item mobile.
package javadesignpatterns.structural.bridge; public class Mobile extends ElectronicItem { public Mobile(Factory factory1, Factory factory2) { super(factory1, factory2); } @Override public void produce() { System.out.print("Mobile "); factory1.production(); factory2.production(); } }
Here we have defined an Interface Factory.java
which is gonna act like an Implementor of bridge pattern.
package javadesignpatterns.structural.bridge; public interface Factory { abstract public void production(); }
The below class CONFIGURED.JAVA
is the concrete implementation of the bridge pattern which is implementing the above interface and overriding the production()
method to configure an item.
package javadesignpatterns.structural.bridge; public class Configured implements Factory { @Override public void production() { System.out.print("Configured"); } }
The below class Released.java
is the concrete implementation of the bridge pattern which is implementing the above interface and overriding the production()
method to release an item.
package javadesignpatterns.structural.bridge; public class Released implements Factory { @Override public void production() { System.out.print(" And"); System.out.println(" Released."); }
Below is the main class BridgePatternTesting.java,
here we are testing the above code by using the Composition to configure and release the Tv and mobile different electronic items,
package javadesignpatterns.structural.bridge; class BridgePatternTesting { public static void main(String[] args) { ElectronicItem item1 = new Tv(new Configured(), new Released()); item1.produce(); ElectronicItem item2 = new Mobile(new Configured(), new Released()); item2.produce(); } }
Conclusion:
I hope it is clear how the Bridge design pattern can reduce the tight coupling between the Abstraction and implementation classes. Please share your feedback in the comments below.