📖 What is the Bridge Pattern? (Simple Explanation)

Bridge Pattern means:

"Separate abstraction from implementation so they can evolve independently."

➡️ Instead of tying two things together tightly (hard-coded),

you connect them through a “bridge” interface.

Think about it like remotely controlling something:

  • The remote control (abstraction)
  • The TV (implementation)

They work together, but you could swap either one independently.


🎨 Real-World Examples (Easy to Visualize)

🎮 1. Game Controller

  • Abstraction: Controller (buttons, joysticks)
  • Implementation: Different consoles (Xbox, PlayStation, Switch)

✅ You can use a controller to operate different consoles if they speak the same "control" language.


🖥️ 2. UI Themes

  • Abstraction: UI Components (Button, Modal, Card)
  • Implementation: Light Theme, Dark Theme, Neon Theme

✅ You can swap the theme without rewriting components.


🚗 3. Vehicle and Engine

  • Abstraction: Vehicle (Car, Truck)
  • Implementation: Engine (PetrolEngine, ElectricEngine)

✅ You can change engines without rebuilding the whole vehicle class.


🖥️ TypeScript Code Example — Remote Control and Devices

Imagine:

  • Remote controls devices (TV, Radio)
  • Devices can be switched on/off independently.

1. Define the Implementation Interface

// Bridge Interface
interface Device {
  turnOn(): void;
  turnOff(): void;
}

2. Concrete Implementations

class TV implements Device {
  turnOn() {
    console.log("TV is now ON");
  }
  turnOff() {
    console.log("TV is now OFF");
  }
}

class Radio implements Device {
  turnOn() {
    console.log("Radio is now ON");
  }
  turnOff() {
    console.log("Radio is now OFF");
  }
}

3. Define the Abstraction

class RemoteControl {
  constructor(protected device: Device) {}

  turnDeviceOn() {
    this.device.turnOn();
  }

  turnDeviceOff() {
    this.device.turnOff();
  }
}

4. Use It

const tv = new TV();
const radio = new Radio();

const tvRemote = new RemoteControl(tv);
tvRemote.turnDeviceOn();   // TV is now ON

const radioRemote = new RemoteControl(radio);
radioRemote.turnDeviceOff(); // Radio is now OFF

🎯 Why Use Bridge Pattern?

Reduce code duplication

Separate concerns (logic vs. implementation)

Swap implementations easily (like device types, database drivers, themes)

Extend without fear (add new devices or new remote functions separately)


✅ Real-World Practical Uses of Bridge

Real-world example Bridge usage
Database Drivers Abstract DatabaseClient (PostgreSQL, MongoDB, MySQL)
Payment Gateways Abstract PaymentService (Stripe, PayPal, Apple Pay)
Cloud Storage Abstract StorageService (AWS S3, Google Cloud, Azure Blob)
Frontend Themes Abstract Theme (Light, Dark, Custom)
Media Players Abstract Player (MP3, MP4, WAV)

📌 Visual Diagram

RemoteControl (Abstraction)
       |
    [uses]
       ↓
TV / Radio (Implementation)

➡️ RemoteControl doesn’t care what device it controls, as long as it matches the Device interface.


📦 Key Pattern Structure (Quick Summary)

// Implementation Interface
interface Implementor { method(): void; }

// Concrete Implementation
class ConcreteImplementorA implements Implementor { method() {} }
class ConcreteImplementorB implements Implementor { method() {} }

// Abstraction
class Abstraction {
  constructor(protected implementor: Implementor) {}

  operation() {
    this.implementor.method();
  }
}

🚀 Important Tip for Senior-Level Usage

When designing large systems:

  • Use Bridge if your abstractions and implementations both need to grow independently.
  • It's better than subclass explosion (too many hardcoded variations).

✅ Flexible, Extensible, and SOLID-friendly!


🌟 Final Summary in One Line

"Bridge pattern separates what you do from how you do it."