Bridge Pattern - Separating Abstraction from Implementation
Master the Bridge pattern for decoupling abstraction from implementation. TypeScript examples for platform-independent rendering, device drivers, and API layers.
Detailed Explanation
Bridge Pattern
The Bridge pattern decouples an abstraction from its implementation so that the two can vary independently. It addresses the problem of class hierarchy explosion when extending functionality in two dimensions.
The Problem: Class Explosion
Without Bridge, combining shapes (Circle, Square) with renderers (SVG, Canvas) requires 4 classes: SVGCircle, SVGSquare, CanvasCircle, CanvasSquare. Adding a third shape adds 2 more. Adding a third renderer adds 3 more. This grows multiplicatively.
Bridge Solution
Split into two independent hierarchies connected by composition:
// Implementation hierarchy
interface Renderer {
drawCircle(x: number, y: number, r: number): string;
drawRect(x: number, y: number, w: number, h: number): string;
}
// Abstraction hierarchy
abstract class Shape {
constructor(protected renderer: Renderer) {}
abstract draw(): string;
}
class Circle extends Shape {
draw() { return this.renderer.drawCircle(0, 0, 5); }
}
Now adding a shape or a renderer is O(1) instead of O(n).
Bridge vs Adapter
Adapter makes existing incompatible interfaces work together (usually applied after design). Bridge is designed up front to let abstraction and implementation vary independently. Adapter is a fix; Bridge is architecture.
Bridge vs Strategy
Both use composition. Bridge separates abstraction from implementation at an architectural level (the "bridge" is permanent). Strategy swaps algorithms at runtime. Bridge typically involves broader interfaces; Strategy usually involves a single method.
When Bridge Shines
Use Bridge when you have a class that needs to work across platforms (web, mobile, desktop), when both the abstraction and implementation are likely to be extended, or when you want to hide implementation details from the client completely.
Use Case
Bridge is ideal for cross-platform UI frameworks (abstract UI components bridged to platform-specific renderers), database drivers (query builder bridged to PostgreSQL/MySQL/SQLite drivers), notification systems (message types bridged to delivery channels), and remote vs local resource access.