LLD - Bridge Design Pattern


Bridge Design Pattern
The Bridge Pattern is a structural design pattern that decouples an abstraction from its implementation, so the two can vary independently.
It’s about composition over inheritance to prevent class explosion when you have multiple variations of a class in two independent dimensions.
Blueprint of Bridge Design Pattern
Abstraction → High-level interface
Refined Abstraction → Specializations
Implementor → Low-level interface
ConcreteImplementor → Specific implementations
Case Study - Notification System
Let’s say you're building a Notification System:
You have types of notifications: Alert, Promotion.
You have multiple delivery channels: Email, SMS, Push.
Approach 1 - The Problem using Inheritance
We will create all the possible combinations using notification types with the delivery channels
Similarly, for Promotion and Reminder, We need to manage 3 × 3 = 9 classes.
This tightly couples abstraction with implementation and makes our system rigid.
What if we try to add a new notification type like Reminder or a new delivery channel like Whatsapp?
This approach creates a combinatorial explosion as new types or channels are added. We will soon have to manage N x M classes.
Approach 2 - Applying the Bridge Pattern
Split this into
Abstraction - Notification
Implementor - Message Sender
Code using Bridge Design Pattern
Github - Bridge Pattern Complete Code
- Implementors
public interface MessageSender {
void sendMessage(String message, String recipient);
}
public class EmailSender implements MessageSender {
public void sendMessage(String message, String recipient) {
System.out.println("Email to " + recipient + ": " + message);
}
}
public class SMSSender implements MessageSender {
public void sendMessage(String message, String recipient) {
System.out.println("SMS to " + recipient + ": " + message);
}
}
Abstraction
public abstract class Notification { protected MessageSender sender; public Notification(MessageSender sender) { this.sender = sender; } public abstract void notifyUser(String message, String recipient); } public class AlertNotification extends Notification { public AlertNotification(MessageSender sender) { super(sender); } public void notifyUser(String message, String recipient) { sender.sendMessage("[ALERT] " + message, recipient); } } public class PromotionNotification extends Notification { public PromotionNotification(MessageSender sender) { super(sender); } public void notifyUser(String message, String recipient) { sender.sendMessage("[PROMO] " + message, recipient); } }
Client
public class NotificationSystemClient {
public static void main(String[] args) {
System.out.println("Notification System : ");
System.out.println("-----------------------");
MessageSender emailSender = new EmailSender();
MessageSender smsSender = new SMSSender();
MessageSender pushSender = new PushSender();
Notification alert = new AlertNotification(emailSender);
alert.notifyUser("Someone has logged in", "pushkar@gmail.com");
Notification sms = new PromotionalNotification(smsSender);
sms.notifyUser("Huge Discount", "+911018789000");
}
}
Benefits of Bridge Pattern
Avoids class explosion
Decouples Abstractions and Implementations
Easier to extend and modify
Best to use when you have two or more dimensions of variation and want better separation of concerns
How is Bridge different from Strategy?
Strategy changes behavior. Bridge separates structure.
Bridge Pattern | Strategy Pattern |
Decouple abstraction from implementation | Define a family of algorithms and make them interchangeable |
There are two independent dimensions of change | You need to switch behavior/algorithm dynamically |
Two class hierarchies: abstraction & implementor | One context class with interchangeable strategy objects |
Subscribe to my newsletter
Read articles from Manish Pushkar directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Manish Pushkar
Manish Pushkar
Software Engineer - Backend