← Back to Home

Bridge Pattern

Decouple an abstraction from its implementation so that the two can vary independently.

What is it?

The Bridge pattern separates an object’s abstraction from its implementation, allowing you to develop them independently. It avoids permanent binding between abstraction and implementation.

Example

interface Renderer {
  renderCircle(radius: number): string;
}

class SVGRenderer implements Renderer {
  renderCircle(radius: number): string {
    return `<svg><circle r="${radius}" /></svg>`;
  }
}

class CanvasRenderer implements Renderer {
  renderCircle(radius: number): string {
    return `Canvas circle with radius ${radius}`;
  }
}

class Shape {
  protected renderer: Renderer;

  constructor(renderer: Renderer) {
    this.renderer = renderer;
  }

  draw(): string {
    return '';
  }
}

class Circle extends Shape {
  private radius: number;

  constructor(radius: number, renderer: Renderer) {
    super(renderer);
    this.radius = radius;
  }

  draw(): string {
    return this.renderer.renderCircle(this.radius);
  }
}

const svg = new SVGRenderer();
const circle = new Circle(10, svg);
console.log(circle.draw());

Common Uses

  • Cross-platform UI rendering
  • Decoupling shape & renderer hierarchies
  • Multiple implementations of an abstraction

When to Use

  • You want to separate abstraction from implementation
  • Need to avoid a Cartesian product of classes

Caution

  • Can add complexity through indirection
  • Needs careful abstraction design