Bridge matters when two dimensions of variation should evolve independently without multiplying subclasses.
Decouple an abstraction from its implementation so the two can vary independently.
What the pattern is trying to do
Decouple an abstraction from its implementation so the two can vary independently.
What force creates the need
A design has at least two orthogonal variation axes, and inheritance would create a growing grid of concrete subclasses.
How the pattern responds
Split the abstraction from the implementation hierarchy and connect them through composition instead of subclass multiplication.
How the moving parts fit together
An abstraction delegates core work to an implementation interface, while refined abstractions and concrete implementors can evolve independently.
Java example in the Order Management domain
package org.javaomnibus.ecommerce.gof.structural;
public interface NotificationSender {
void send(String recipient, String message);
}
public final class EmailSender implements NotificationSender {
@Override
public void send(String recipient, String message) {}
}
public abstract class OrderNotification {
protected final NotificationSender sender;
protected OrderNotification(NotificationSender sender) {
this.sender = sender;
}
public abstract void notifyCustomer(String customerContact);
}
public final class ShipmentNotification extends OrderNotification {
public ShipmentNotification(NotificationSender sender) {
super(sender);
}
@Override
public void notifyCustomer(String customerContact) {
sender.send(customerContact, "Your shipment is on the way.");
}
}
Step by step
- OrderNotification is the abstraction side.
- NotificationSender is the implementation side.
- ShipmentNotification and EmailSender can vary without creating a subclass for every combination.
- Bridge is useful when the two variation axes are both real and stable enough to separate cleanly.
Where this pattern helps
- When two independent dimensions of change keep intersecting in awkward inheritance trees
- When you want runtime composition between abstraction and implementation families
When a simpler design is better
- When there is only one meaningful axis of change
- When the split would be artificial and add ceremony without reducing complexity
What this pattern costs
- Adds abstraction layers that can feel heavy in small designs
- Requires good judgment about what the true independent dimensions really are
How this fits today
Bridge is still relevant in Java where platform integration, messaging channels, storage engines, or rendering outputs vary independently from higher-level business abstractions.
Where teams get it wrong
Splitting a design into abstraction and implementation hierarchies too early creates complexity when only one side is truly changing.