Bridge Design Pattern

Last Updated : 7 May, 2026

The Bridge Design Pattern is a structural design pattern that separates an abstraction from its implementation so that both can vary independently. It helps avoid tight coupling between abstraction and implementation, making the system more flexible and extensible.

  • Decouples abstraction from implementation using composition instead of inheritance, allowing both to be developed and extended independently.
  • Ensures changes in implementation do not affect client code, improving flexibility and maintainability.

There are 2 parts in Bridge design pattern.

  1. Abstraction
  2. Implementation
abstraction
UML Diagram

Example: Consider a remote control system where a remote can operate different devices like a TV or a Light. Instead of creating separate remotes for each device, the Bridge Pattern separates the remote (abstraction) from the device (implementation). This allows the same remote to control different devices independently. You can extend remotes or add new devices without changing existing code.

abstraction-

In the Diagram:

  • The Remote (Abstraction) holds a reference to a Device (Implementation) like TV or Light.
  • The remote delegates actions (turn on/off, volume, brightness) to the connected device.
  • New remotes or devices can be added independently without modifying existing classes.

Real-Life Applications

Bridge pattern is often used when you want to separate abstraction from its implementation to allow independent variation. Some common examples include:

  • Remote Control and Devices: A universal remote (abstraction) can control multiple types of devices (TV, Radio, AC). The remote doesn’t care about the internal workings of the device; it just sends commands through a common interface. Each device has its own implementation of turning on, off, or changing channels/volume.
  • Shapes and Colors in Graphics: A Shape (abstraction) like Circle or Rectangle can use different Color implementations (Red, Blue). Shapes don’t handle color details they delegate drawing to the color implementation.

Components

The bridge design pattern separates abstraction from implementation, allowing them to vary independently.

  • Abstraction: core of the bridge design pattern and defines the crux. Contains a reference to the implementer.
  • Refined Abstraction: Extends the abstraction takes the finer detail one level below. Hides the finer elements from implementers.
  • Implementer: It defines the interface for implementation classes. This interface does not need to correspond directly to the abstraction interface and can be very different.
  • Concrete Implementation: Implements the above implementer by providing the concrete implementation.

Working

The Bridge Pattern works by delegating implementation-specific work to a separate interface.

  • The abstraction contains a reference to the implementation interface.
  • Concrete implementations provide the actual behavior.
  • The client interacts only with the abstraction, not the implementation.

Uses

The Bridge Pattern is used when abstraction and implementation need to evolve independently.

  • When you want to avoid permanent binding between abstraction and implementation.
  • When changes in implementation should not affect client code.
  • When you want to hide implementation details from the client.

Implementation Example

Vehicle is the abstraction, and Car and Bike are refined abstractions. The Workshop interface defines the implementation, with Produce and Assemble as concrete implementations. This allows vehicles and workshops to vary independently e.g., a Car can be produced and assembled without changing the Bike class. 

C++
#include <iostream>
using namespace std;

class Workshop {
public:
    virtual void work() = 0;
};

class Produce : public Workshop {
public:
    void work() override {
        cout << "Produced";
    }
};

class Assemble : public Workshop {
public:
    void work() override {
        cout << " And";
        cout << " Assembled." << endl;
    }
};

class Vehicle {
protected:
    Workshop* workShop1;
    Workshop* workShop2;

public:
    Vehicle(Workshop* workShop1, Workshop* workShop2) {
        this->workShop1 = workShop1;
        this->workShop2 = workShop2;
    }
    virtual void manufacture() = 0;
};

class Car : public Vehicle {
public:
    Car(Workshop* workShop1, Workshop* workShop2) : Vehicle(workShop1, workShop2) {}
    void manufacture() override {
        cout << "Car ";
        workShop1->work();
        workShop2->work();
    }
};

class Bike : public Vehicle {
public:
    Bike(Workshop* workShop1, Workshop* workShop2) : Vehicle(workShop1, workShop2) {}
    void manufacture() override {
        cout << "Bike ";
        workShop1->work();
        workShop2->work();
    }
};

int main() {
    Vehicle* vehicle1 = new Car(new Produce(), new Assemble());
    vehicle1->manufacture();
    Vehicle* vehicle2 = new Bike(new Produce(), new Assemble());
    vehicle2->manufacture();
    return 0;
}
Java
abstract class Vehicle {
    protected Workshop workShop1;
    protected Workshop workShop2;

    protected Vehicle(Workshop workShop1, Workshop workShop2)
    {
        this.workShop1 = workShop1;
        this.workShop2 = workShop2;
    }

    abstract public void manufacture();
}

// Refine abstraction 1 in bridge pattern
class Car extends Vehicle {
    public Car(Workshop workShop1, Workshop workShop2)
    {
        super(workShop1, workShop2);
    }

    @Override
    public void manufacture()
    {
        System.out.print("Car ");
        workShop1.work();
        workShop2.work();
    }
}

// Refine abstraction 2 in bridge pattern
class Bike extends Vehicle {
    public Bike(Workshop workShop1, Workshop workShop2)
    {
        super(workShop1, workShop2);
    }

    @Override
    public void manufacture()
    {
        System.out.print("Bike ");
        workShop1.work();
        workShop2.work();
    }
}

// Implementer for bridge pattern
interface Workshop
{
    abstract public void work();
}

// Concrete implementation 1 for bridge pattern
class Produce implements Workshop {
    @Override
    public void work()
    {
        System.out.print("Produced");
    }
}

// Concrete implementation 2 for bridge pattern
class Assemble implements Workshop {
    @Override
    public void work()
    {
        System.out.print(" And");
        System.out.println(" Assembled.");
    }
}

// Demonstration of bridge design pattern
class BridgePattern {
    public static void main(String[] args)
    {
        Vehicle vehicle1 = new Car(new Produce(), new Assemble());
        vehicle1.manufacture();
        Vehicle vehicle2 = new Bike(new Produce(), new Assemble());
        vehicle2.manufacture();
    }
}
Python
from abc import ABC, abstractmethod

class Workshop(ABC):
    @abstractmethod
    def work(self):
        pass

class Produce(Workshop):
    def work(self):
        print('Produced', end='')

class Assemble(Workshop):
    def work(self):
        print(' And', end='')
        print(' Assembled.')

class Vehicle(ABC):
    def __init__(self, workShop1, workShop2):
        self.workShop1 = workShop1
        self.workShop2 = workShop2

    @abstractmethod
    def manufacture(self):
        pass

class Car(Vehicle):
    def manufacture(self):
        print('Car', end=' ')
        self.workShop1.work()
        self.workShop2.work()

class Bike(Vehicle):
    def manufacture(self):
        print('Bike', end=' ')
        self.workShop1.work()
        self.workShop2.work()

if __name__ == '__main__':
    vehicle1 = Car(Produce(), Assemble())
    vehicle1.manufacture()
    vehicle2 = Bike(Produce(), Assemble())
    vehicle2.manufacture()
JavaScript
class Workshop {
    work() {
        throw new Error('Method not implemented.');
    }
}

class Produce extends Workshop {
    work() {
        process.stdout.write('Produced');
    }
}

class Assemble extends Workshop {
    work() {
        process.stdout.write(' And');
        console.log(' Assembled.');
    }
}

class Vehicle {
    constructor(workShop1, workShop2) {
        this.workShop1 = workShop1;
        this.workShop2 = workShop2;
    }
    manufacture() {
        throw new Error('Method not implemented.');
    }
}

class Car extends Vehicle {
    manufacture() {
        process.stdout.write('Car ');
        this.workShop1.work();
        this.workShop2.work();
    }
}

class Bike extends Vehicle {
    manufacture() {
        process.stdout.write('Bike ');
        this.workShop1.work();
        this.workShop2.work();
    }
}

const vehicle1 = new Car(new Produce(), new Assemble());
vehicle1.manufacture();
const vehicle2 = new Bike(new Produce(), new Assemble());
vehicle2.manufacture();

Output : 

Car Produced And Assembled.
Bike Produced And Assembled.

Here we're producing and assembling the two different vehicles using Bridge design pattern.

Need of bridge design pattern

The Bridge pattern is an application of the old advice, "prefer composition over inheritance". It becomes handy when you must subclass different times in ways that are orthogonal with one another.
For Example, the above example can also be done something like this : 

Without Bridge Design Pattern 

bus

But the above solution has a problem. If you want to change the Bus class, then you may end up changing ProduceBus and AssembleBus as well and if the change is workshop specific then you may need to change the Bike class as well.

With Bridge Design Pattern

You can solve the above problem by decoupling the Vehicle and Workshop interfaces in the below manner.

vehicle

Advantages

The Bridge Pattern provides flexibility and better code organization by separating abstraction from implementation.

  • Reduces tight coupling between abstraction and implementation.
  • Allows independent extension of both abstraction and implementation.
  • Improves maintainability and scalability of the system.

Disadvantages

Despite its benefits, the Bridge Pattern can introduce some complexity.

  • Increases initial design complexity due to additional interfaces and classes.
  • May be unnecessary for simple applications.
  • Can make the code harder to understand for beginners.

Also check

Comment

Explore