Understanding the Bridge Pattern: Decoupling Abstraction and Implementation
The Bridge Pattern is a structural design pattern that decouples an abstraction (what you do) from its implementation (how you do it), allowing the two to vary independently. Itโs an elegant solution to avoid a accumulation of classes when dealing with multiple dimensions of change in a system.
This article will explore the Bridge Pattern through a relatable scenario, delve into its purpose, and provide a TypeScript implementation to solidify your understanding.
Table of Contents
1.Bridge Pattern Definition
The Bridge Pattern decouples the abstraction (high-level control) from its implementation (low-level details). This separation enables the abstraction and implementation to evolve independently, reducing the rigidity of tightly coupled code and enhancing flexibility and scalability.
2.Scenario: Understanding the Problem
Imagine a company that manufactures vehicles. Each vehicle can have different types of engines (e.g., petrol, diesel, electric). Without a flexible design, you might end up creating a class for every combination of vehicle type and engine type, leading to a bloated and unmanageable codebase.
For example:
CarWithPetrolEngine
CarWithDieselEngine
TruckWithElectricEngine
The Bridge Pattern addresses this by separating the Vehicle abstraction from the Engine implementation, allowing you to combine them dynamically without creating an excessive number of classes.
Implementation in TypeScript
Hereโs how the Bridge Pattern can be implemented in TypeScript:
// Implementor Interface
interface Engine {
start(): string;
}
// Concrete Implementors
class PetrolEngine implements Engine {
start(): string {
return "Starting petrol engine";
}
}
class DieselEngine implements Engine {
start(): string {
return "Starting diesel engine";
}
}
class ElectricEngine implements Engine {
start(): string {
return "Starting electric engine";
}
}
// Abstraction
abstract class Vehicle {
protected engine: Engine;
constructor(engine: Engine) {
this.engine = engine;
}
abstract operate(): string;
}
// Refined Abstraction
class Car extends Vehicle {
operate(): string {
return `Car operating: ${this.engine.start()}`;
}
}
class Truck extends Vehicle {
operate(): string {
return `Truck operating: ${this.engine.start()}`;
}
}
// Client Code
const petrolCar = new Car(new PetrolEngine());
console.log(petrolCar.operate());
const electricTruck = new Truck(new ElectricEngine());
console.log(electricTruck.operate());
Output:
Car operating: Starting petrol engine
Truck operating: Starting electric engine
3.Real-Life Projects That Use the Bridge Pattern
Graphics Rendering Systems: Separating shapes (e.g., circle, rectangle) from rendering logic (e.g., OpenGL, DirectX) for flexibility.
Device Control Systems: Abstracting devices (e.g., remotes) from the objects they control (e.g., TVs, projectors).
Conclusion
By using the Bridge Pattern, you can simplify code management, reduce duplication, and create systems that are flexible enough to adapt to change.
In the next article of our Learn Design Patterns series, weโll explore the Composite Pattern Stay tuned!
Top comments (0)