Bridge Pattern

Intent
"Decouple an abstraction from its implementation so that the two can vary independently." — Gang of Four (GoF)
Problem
Plaintext
Circle × Red
Circle × Blue
Square × Red
Square × Blue
... and so on.
Solution
- One for abstractions (e.g., shapes, remotes)
- One for implementations (e.g., colors, devices)
Real-world Analogy
Structure
Plaintext
Abstraction
└── RefinedAbstraction
└── implementation: Implementation
Implementation (interface)
├── ConcreteImplementationA
└── ConcreteImplementationB
TypeScript Example – Devices and Remotes
Device interface (Implementation)
Ts
interface Device {
isEnabled(): boolean;
enable(): void;
disable(): void;
getVolume(): number;
setVolume(percent: number): void;
getChannel(): number;
setChannel(channel: number): void;
}
Concrete Devices
Ts
class TV implements Device {
private on = false;
private volume = 50;
private channel = 1;
isEnabled(): boolean {
return this.on;
}
enable(): void {
this.on = true;
console.log("TV is now ON");
}
disable(): void {
this.on = false;
console.log("TV is now OFF");
}
getVolume(): number {
return this.volume;
}
setVolume(percent: number): void {
this.volume = Math.min(Math.max(percent, 0), 100);
console.log(`TV volume set to ${this.volume}`);
}
getChannel(): number {
return this.channel;
}
setChannel(channel: number): void {
this.channel = channel;
console.log(`TV channel set to ${this.channel}`);
}
}
Remote Control (Abstraction)
Ts
class RemoteControl {
constructor(protected device: Device) {}
togglePower(): void {
this.device.isEnabled() ? this.device.disable() : this.device.enable();
}
volumeDown(): void {
this.device.setVolume(this.device.getVolume() - 10);
}
volumeUp(): void {
this.device.setVolume(this.device.getVolume() + 10);
}
channelDown(): void {
this.device.setChannel(this.device.getChannel() - 1);
}
channelUp(): void {
this.device.setChannel(this.device.getChannel() + 1);
}
}
Advanced Remote (Refined Abstraction)
Ts
class AdvancedRemoteControl extends RemoteControl {
mute(): void {
this.device.setVolume(0);
console.log("Muted");
}
}
Usage
Ts
const tv = new TV();
const remote = new RemoteControl(tv);
remote.togglePower(); // TV is now ON
remote.volumeUp(); // TV volume set to 60
remote.channelUp(); // TV channel set to 2
const smartRemote = new AdvancedRemoteControl(tv);
smartRemote.mute(); // Muted, volume = 0
When to Use
- You need to decouple abstraction and implementation.
- You want to avoid a class explosion when extending in multiple dimensions.
- You need to change implementations at runtime.
- You want to develop parts independently (e.g., UI vs backend).
Pros & Cons
- Open/Closed Principle: add new abstractions/implementations without changes.
- Improves modularity and flexibility.
- You can reuse abstractions with many implementations.
- Adds complexity due to additional interfaces and indirection.
- May be overkill if only one dimension of variation exists.