The Bridge Pattern in Java

Introduction to the Bridge Pattern

Design pattern in a simple meaning, is a way to design reusable object-oriented code. We can think of ways to design our classes, interfaces, enums and their members so that the code is reusable but flexible.

There are 23 most important design patterns, pioneered by the book Design Patterns: Elements of Reusable Object-Oriented Software, written by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides or Gang of Four for short. We will cover these design pattern one by one.

Bridge pattern is used when we need to decouple an abstraction from its implementation so that the two can vary independently. While the way the GoF put it seems so hard to understand, in fact this pattern is very simple.

Implementation of Bridge Pattern in Java

Say we have an abstract Shape class, which has some subclasses, e.g Circle class and Square class and Triangle class … Now each Shape object also implements an interface, the ShapeColor interface. In src folder first we create ShapeColor interface:

public interface ShapeColor {
  void fill();
}

And then the abstract Shape class:

public abstract class Shape implements ShapeColor{
  abstract void draw();
}

Say we have two Shape colors possible, red and blue. So for example we can create a CircleRed class like this:

public class CircleRed extends Shape{
  void draw() {
    System.out.print("draw a circle ");
  }
  public void fill() {
    System.out.println("and fill with Red");
  }
}

And a SquareBlue class like this:

public class SquareBlue extends Shape{
  void draw() {
    System.out.print("draw a square ");
  }
  public void fill() {
    System.out.println("and fill with Blue");
  }
}

Ok, in Test.java we can use the concrete classes:

public class Test{
  public static void main(String... args){
    CircleRed circleRed = new CircleRed();
    circleRed.draw();
    circleRed.fill();
    SquareBlue squareBlue = new SquareBlue();
    squareBlue.draw();
    squareBlue.fill();
  }
}

Run the Test.java and we have the output:

draw a circle and fill with Red
draw a square and fill with Blue

This is OK, but with the Bridge pattern, we have a better way. We will detach the ShapeColor interface from its implementation. To do that first we create two concrete class that implement the ShapeColor, the ShapeColorBlue.java:

public class ShapeColorBlue implements ShapeColor{
  public void fill() {
    System.out.println("and fill with Blue");
  }
}

and the ShapeColorRed.java:

public class ShapeColorRed implements ShapeColor{
  public void fill() {
    System.out.println("and fill with Red");
  }
}

And in Shape class, instead of implementing the ShapeColor interface, we will compose the ShapeColor interface into the Shape class:

public abstract class Shape{
  protected ShapeColor shapeColor;
  public Shape(ShapeColor shapeColor) {
    this.shapeColor = shapeColor;
  }
  abstract void draw();
}

Now instead of creating a CircleRed, we will create a Circle class that accepts a ShapeColor object as the parameter in the constructor. When we need to create the Circle that’s filled in red, we simply create it dynamically:

public class Circle extends Shape{
  public Circle(ShapeColor shapeColor) {
    super(shapeColor);
  }
  void draw() {
    System.out.print("draw a square ");
    shapeColor.fill();
  }
}

We do the same with Square class:

public class Square extends Shape{
  public Square(ShapeColor shapeColor) {
    super(shapeColor);
  }
  void draw() {
    System.out.print("draw a circle ");
    shapeColor.fill();
  }
}

Now, in Test.java, we will create red Circle and blue Square dynamically:

public class Test{
  public static void main(String... args){
    Circle circleRed = new Circle(
        new ShapeColorRed()
    );
    circleRed.draw();
    Square squareBlue = new Square(
        new ShapeColorBlue()
    );
    squareBlue.draw();
  }
}

Run the Test.java:

draw a circle and fill with Red
draw a square and fill with Blue

 

Leave a Reply