Bridge Design Pattern in JavaScript

1. Definition

The Bridge Design Pattern aims to separate an abstraction from its implementation so that the two can evolve independently. It decouples an abstraction from its implementation, providing two independent hierarchies.

2. Problem Statement

Imagine you have a shape class like a circle, and you want to extend it for different colors. If you keep extending for each variant (like RedCircle, and BlueCircle), the class hierarchy can grow quickly, making it less maintainable and more complex.

3. Solution

The Bridge pattern recommends splitting the monolithic class into separate class hierarchies. In this context, one hierarchy deals with the basic shape, while the other hierarchy deals with colors. You then use composition to bridge the two hierarchies together.

4. Real-World Use Cases

1. Remote controls and devices: Different remote controls can have different implementations, but all need to control a set of devices. The bridge pattern can separate the remote control 'abstraction' from the device 'implementation'.

2. Platform-independent graphics and rendering.

3. Webpage themes: Where the content remains the same, but the style (theme) can be switched out.

5. Implementation Steps

1. Identify the larger class hierarchy and break it into two separate hierarchies — abstraction and implementation.

2. Create an interface for the implementation hierarchy.

3. The abstraction class should have a reference to the implementation class.

4. The client should be able to pair any abstraction with any implementation at runtime.

6. Implementation in JavaScript

// Implementor for the color hierarchy
function Color() {
  this.applyColor = function() {};
}
function RedColor() {
  this.applyColor = function() {
    return 'Red';
  };
}
function BlueColor() {
  this.applyColor = function() {
    return 'Blue';
  };
}
// Abstraction for the shape hierarchy
function Shape(color) {
  this.color = color;
}
Shape.prototype.draw = function() {
  return this.color.applyColor() + ' ' + this.getShapeType();
};
function Circle(color) {
  Shape.call(this, color);
}
Circle.prototype = Object.create(Shape.prototype);
Circle.prototype.getShapeType = function() {
  return 'Circle';
};
// Client code
const red = new RedColor();
const blue = new BlueColor();
const redCircle = new Circle(red);
const blueCircle = new Circle(blue);
console.log(redCircle.draw());
console.log(blueCircle.draw());

Output:

Red Circle
Blue Circle

Explanation:

1. Color serves as the base class for the implementor hierarchy, with two derived classes RedColor and BlueColor.

2. Shape serves as the base class for the abstraction hierarchy. It has a reference to a Color object.

3. Circle is a concrete shape. It uses the draw method to apply the color and define the type of shape.

4. In the client code, we combine a color (implementation) with a shape (abstraction) to get the desired object.

7. When to use?

Use the Bridge pattern when:

1. You want to avoid a permanent binding between an abstraction and its implementation.

2. Both the abstractions and their implementations should be extensible through subclassing.

3. Changes in the implementation of an abstraction should not impact the clients.


Comments