Problem
Abstraction? Implementation? Sound scary? Stay calm and let’s consider a simple example.
Shape
class with a pair of subclasses: Circle
and Square
. You want to extend this class hierarchy to incorporate colors, so you plan to create Red
and Blue
shape subclasses. However, since you already have two subclasses, you’ll need to create four class combinations such as BlueCircle
and RedSquare
.Adding new shape types and colors to the hierarchy will grow it exponentially. For example, to add a triangle shape you’d need to introduce two subclasses, one for each color. And after that, adding a new color would require creating three subclasses, one for each shape type. The further we go, the worse it becomes.
Solution
This problem occurs because we’re trying to extend the shape classes in two independent dimensions: by form and by color. That’s a very common issue with class inheritance.
The Bridge pattern attempts to solve this problem by switching from inheritance to the object composition. What this means is that you extract one of the dimensions into a separate class hierarchy, so that the original classes will reference an object of the new hierarchy, instead of having all of its state and behaviors within one class.
Following this approach, we can extract the color-related code into its own class with two subclasses: Red
and Blue
.
The Shape
class then gets a reference field pointing to one of the color objects. Now the shape can delegate any color-related work to the linked color object.
That reference will act as a bridge between the Shape
and Color
classes. From now on, adding new colors won’t require changing the shape hierarchy, and vice versa.
Structure
Pros and Cons
Bridge Design Pattern Example
Color.Java
public interface Color { public void applyColor(); }
Shape.Java
public abstract class Shape { //Composition - implementor protected Color color; //constructor with implementor as input argument public Shape(Color c){ this.color=c; } abstract public void applyColor(); }
Triangle.java
public class Triangle extends Shape{ public Triangle(Color c) { super(c); } @Override public void applyColor() { System.out.print("Triangle filled with color "); color.applyColor(); } }
Pentagon.Java;
public class Pentagon extends Shape{ public Pentagon(Color c) { super(c); } @Override public void applyColor() { System.out.print("Pentagon filled with color "); color.applyColor(); } }
Here are the implementation classes for RedColor and GreenColorRedColor.Java
public class RedColor implements Color{ public void applyColor(){ System.out.println("red."); } }
GreenColor.Java
class GreenColor implements Color{ public void applyColor(){ System.out.println("green."); } }
Lets test our bridge pattern implementation with a test program.public class BridgePatternTest { public static void main(String[] args) { Shape tri = new Triangle(new RedColor()); tri.applyColor(); Shape pent = new Pentagon(new GreenColor()); pent.applyColor(); } }
Output of above bridge pattern example program is:Triangle filled with color red.
Pentagon filled with color green.