Bridge Pattern

25 Jul 2026, Updated: 26 Jul 2026 4 min read
1
The Bridge Pattern is a structural design pattern that separates an abstraction from its implementation so that both can evolve independently.

Instead of tightly coupling an abstraction to a specific implementation through inheritance, the Bridge Pattern connects them using composition. The abstraction maintains a reference to an implementation object and delegates work to it.

This approach allows new abstractions and implementations to be introduced independently without creating a large hierarchy of subclasses.

The Bridge Pattern is commonly used when applications need to support multiple implementations of the same functionality, such as different databases, messaging providers, rendering engines, or payment gateways.

Structure

The Bridge Pattern consists of the following participants.

1. The Abstraction defines the high-level interface used by the client.
2. The Refined Abstraction extends the abstraction with additional behaviour.
3. The Implementor defines the interface for the implementation.
4. Concrete Implementors provide different implementations of the implementor interface.

Java Implementation

Suppose an application sends notifications through different communication channels.

The notification type (Alert or Reminder) should be independent of the delivery mechanism (Email or SMS). Create the implementor interface.
public interface MessageSender {
    void send(String message);
}
Create the concrete implementors.
public class EmailSender implements MessageSender {
    @Override
    public void send(String message) {
        System.out.println("Sending Email: " + message);
    }
}
public class SmsSender implements MessageSender {
    @Override
    public void send(String message) {
        System.out.println("Sending SMS: " + message);
    }
}
Create the abstraction.
public abstract class Notification {
    protected final MessageSender sender;

    protected Notification(MessageSender sender) {
        this.sender = sender;
    }

    public abstract void notifyUser(String message);
}
Create the refined abstractions.
public class AlertNotification extends Notification {
    public AlertNotification(MessageSender sender) {
        super(sender);
    }

    @Override
    public void notifyUser(String message) {
        sender.send("ALERT: " + message);
    }
}
public class ReminderNotification extends Notification {
    public ReminderNotification(MessageSender sender) {
        super(sender);
    }

    @Override
    public void notifyUser(String message) {
        sender.send("REMINDER: " + message);
    }
}
The client combines any notification type with any message sender.
public class Main {
    public static void main(String[] args) {
        Notification notification = new AlertNotification(new EmailSender());
        notification.notifyUser("Server CPU usage is high.");
    }
}
Output:
Sending Email: ALERT: Server CPU usage is high.

How It Works?

The client creates a concrete implementation of the MessageSender interface, such as EmailSender or SmsSender.

A concrete notification, such as AlertNotification, receives the implementation object through its constructor. Rather than performing the delivery itself, it delegates the operation to the associated message sender.

Because the abstraction and implementation are independent, any notification type can work with any message sender. For example, an alert can be sent through Email or SMS without creating additional subclasses.

This separation prevents an explosion of subclasses and allows both hierarchies to evolve independently.

Advantages

1. It separates abstraction from implementation using composition.
2. Abstractions and implementations can evolve independently.
3. It avoids large inheritance hierarchies.
4. New abstractions and implementations can be added without affecting existing code.

Disadvantages

1. The pattern introduces additional interfaces and classes.
2. It may be unnecessary for simple applications with only one implementation.
3. Understanding the separation between abstraction and implementation may require additional effort.

JDK Examples

The Bridge Pattern appears throughout the Java ecosystem.

1. The java.sql.DriverManager works with different JDBC driver implementations through common interfaces, allowing applications to switch database vendors without changing client code.

2. The java.util.logging.Handler hierarchy separates logging behaviour from the destination where log records are written, such as the console or a file.

Summary

The Bridge Pattern separates an abstraction from its implementation so that both can vary independently.

By favouring composition over inheritance, the pattern improves flexibility, reduces subclass proliferation, and makes applications easier to extend and maintain when multiple implementations must coexist.
Nagesh Chauhan

Nagesh Chauhan

Principal Software Engineer • Java • Python • Distributed Systems • AI/ML

Principal Software Engineer with 14+ years of experience designing and delivering large-scale distributed systems, cloud-native applications, and AI-powered platforms.

Passionate about solving complex engineering problems using strong data structures and algorithms, along with expertise in Java, Spring Boot, Python, System Design, Microservices, Cloud, Kafka, Elasticsearch, and Generative AI.

Share this Article

💬 Comments

Join the Discussion