DEV Community

Cover image for Understanding the Bridge Pattern: Decoupling Abstraction and Implementation
Sami Maachi
Sami Maachi

Posted on

Understanding the Bridge Pattern: Decoupling Abstraction and Implementation

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

  2. Scenario: Understanding the Problem

  3. Real-Life Projects That Use the Bridge Pattern

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()); 
Enter fullscreen mode Exit fullscreen mode
    Output:
    Car operating: Starting petrol engine
    Truck operating: Starting electric engine
Enter fullscreen mode Exit fullscreen mode

3.Real-Life Projects That Use the Bridge Pattern

  1. Graphics Rendering Systems: Separating shapes (e.g., circle, rectangle) from rendering logic (e.g., OpenGL, DirectX) for flexibility.

  2. 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)