📖 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."