As we know that Structural Design Patterns are concerned with the composition of classes and objects. They focus on how to assemble classes and objects into larger structures while keeping these structures flexible and efficient. Bridge Pattern is one of the most important structural design pattern.
What is the Bridge Pattern?
The Bridge pattern separates an object's abstraction (high-level part) from its implementation (low-level operations).
Instead of binding abstraction and implementation permanently, Bridges uses composition to connect them, making the system more flexible.
Problem Without Bridge
Suppose we have different Car types (e.g., Sedan, SUV, Hatchback) and different Engine types (e.g., Petrol Engine, Diesel Engine, Electric Engine).
If we directly use inheritance, we will need a class for each combination:
SedanWithPetrolEngine
SedanWithDieselEngine
SedanWIthElectricEngine
SUVWithPetrolEngine
SUVWithDieselEngine
SUVWithElectricEngine
And if tomorrow we add CNG Engine, we will need two more classes.
This leads to class explosion -> difficult to manage and extend.
Example Code Without Bridge:
#include <iostream>
using namespace std;
// Sedan with Petrol Engine
class SedanPetrol {
public:
void drive() { cout << "Driving Sedan with Petrol Engine\n"; }
};
// Sedan with Diesel Engine
class SedanDiesel {
public:
void drive() { cout << "Driving Sedan with Diesel Engine\n"; }
};
// SUV with Petrol Engine
class SUVPetrol {
public:
void drive() { cout << "Driving SUV with Petrol Engine\n"; }
};
// SUV with Diesel Engine
class SUVDiesel {
public:
void drive() { cout << "Driving SUV with Diesel Engine\n"; }
};
int main() {
SedanPetrol sedanPetrol;
sedanPetrol.drive();
SUVDiesel suvDiesel;
suvDiesel.drive();
return 0;
}
Output:
Driving Sedan with Petrol Engine
Driving SUV with Diesel Engine
Problems:
- Class Explosion: For
n
car types *m
engine types, we getn*m
classes. - Tight Coupling: Car and engine are bound together, can't reuse independently.
- Hard to Extend: Adding a new engine requires modifying or creating many classes.
Solution With Bridge Pattern
With a Bridge Pattern, we separate:
- Abstraction (Car) – Represents different card types (Sedan, SUV).
- Implementor (Engine) – Represents different engine types (Petrol, Diesel, Electric).
Cars uses engines via composition, not inheritance.
#include <iostream>
using namespace std;
// Implementor (Engine Interface)
class Engine {
public:
virtual void start() = 0;
virtual ~Engine() = default;
};
// Concrete Implementors
class PetrolEngine : public Engine {
public:
void start() override { cout << "Starting Petrol Engine\n"; }
};
class DieselEngine : public Engine {
public:
void start() override { cout << "Starting Diesel Engine\n"; }
};
class ElectricEngine : public Engine {
public:
void start() override { cout << "Starting Electric Engine\n"; }
};
// Abstraction (Car)
class Car {
protected:
Engine* engine; // Bridge
public:
Car(Engine* eng) : engine(eng) {}
virtual void drive() = 0;
virtual ~Car() = default;
};
// Refined Abstractions
class Sedan : public Car {
public:
Sedan(Engine* eng) : Car(eng) {}
void drive() override {
cout << "Sedan is driving... ";
engine->start();
}
};
class SUV : public Car {
public:
SUV(Engine* eng) : Car(eng) {}
void drive() override {
cout << "SUV is driving... ";
engine->start();
}
};
int main() {
PetrolEngine petrol;
DieselEngine diesel;
ElectricEngine electric;
Sedan sedan1(&petrol);
Sedan sedan2(&electric);
SUV suv1(&diesel);
SUV suv2(&petrol);
sedan1.drive();
sedan2.drive();
suv1.drive();
suv2.drive();
return 0;
}
Output:
Sedan is driving... Starting Petrol Engine
Sedan is driving... Starting Electric Engine
SUV is driving... Starting Diesel Engine
SUV is driving... Starting Petrol Engine
Benefits of Bridge Here
- No class explosion: Only
n + m
classes (Cars + Engines) instead ofn * m
. - Loose coupling: Car types and Engines types are independently.
- Easy to extend: Adding a new engine or car type requires only one new class.
Leave a comment
Your email address will not be published. Required fields are marked *