Bridge Pattern
Separate abstraction from implementation to vary them independently
Pattern Overview
🌉 Bridge Pattern
The Bridge Pattern decouples an abstraction from its implementation so that both can vary independently. It creates a "bridge" between the abstraction and implementation hierarchies.
Core Concepts
🔹 Abstraction - High-level interface that clients use
🔹 Implementation - Low-level interface for concrete operations
🔹 Bridge - Connection that allows abstraction to use any implementation
🔹 Independence - Both sides can evolve separately
Real-World Applications
Graphics Systems - Shapes can use different rendering engines (SVG, Canvas, OpenGL) Database Access - Repository pattern works with different database drivers Messaging Systems - Message types can use different delivery channels Device Drivers - Abstract device operations work with specific hardwareImplementation Benefits
✅ Platform independence - Switch implementations without changing client code
✅ Runtime flexibility - Change implementation at runtime
✅ Separate concerns - Abstraction and implementation evolve independently
✅ Reduces coupling - Client depends only on abstraction interface
Examples:
circle.draw() with SVG and Canvas renderersDifferent rendering outputs based on implementationtextMessage.send() with email and Slack sendersMessages sent through different channelsrepository.findUser() with MySQL and PostgreSQLDatabase-specific SQL queriesConcepts
Complexity Analysis
Implementation
graphics-rendering
// Implementation hierarchy
interface DrawingAPI {
drawCircle(x: number, y: number, radius: number): string;
drawRectangle(x: number, y: number, width: number, height: number): string;
}
class SVGRenderer implements DrawingAPI {
drawCircle(x: number, y: number, radius: number): string {
return `<circle cx="${x}" cy="${y}" r="${radius}" />`;
}
drawRectangle(x: number, y: number, width: number, height: number): string {
return `<rect x="${x}" y="${y}" width="${width}" height="${height}" />`;
}
}
class CanvasRenderer implements DrawingAPI {
drawCircle(x: number, y: number, radius: number): string {
return `ctx.arc(${x}, ${y}, ${radius}, 0, 2 * Math.PI);`;
}
drawRectangle(x: number, y: number, width: number, height: number): string {
return `ctx.fillRect(${x}, ${y}, ${width}, ${height});`;
}
}
// Abstraction hierarchy
abstract class Shape {
protected renderer: DrawingAPI;
constructor(renderer: DrawingAPI) {
this.renderer = renderer;
}
setRenderer(renderer: DrawingAPI): void {
this.renderer = renderer;
}
abstract draw(): string;
}
class Circle extends Shape {
constructor(private x: number, private y: number, private radius: number, renderer: DrawingAPI) {
super(renderer);
}
draw(): string {
return this.renderer.drawCircle(this.x, this.y, this.radius);
}
}
class Rectangle extends Shape {
constructor(private x: number, private y: number, private width: number, private height: number, renderer: DrawingAPI) {
super(renderer);
}
draw(): string {
return this.renderer.drawRectangle(this.x, this.y, this.width, this.height);
}
}
// Usage
const svgRenderer = new SVGRenderer();
const canvasRenderer = new CanvasRenderer();
const circle = new Circle(100, 100, 50, svgRenderer);
console.log(circle.draw()); // SVG output
circle.setRenderer(canvasRenderer);
console.log(circle.draw()); // Canvas output