Bridge Pattern
AdvancedDecouples an abstraction from its implementation so that the two can vary independently.
Overview
The Bridge pattern avoids a Cartesian product class explosion when you have two independent dimensions of variation. Without Bridge: Shape (Circle, Square) × Rendering (Vector, Raster) = 4 classes. With Bridge: Shape holds a reference to Renderer — 2 + 2 = 4 classes instead of 4, but adding a new Shape costs 1 class (not N renderer variants), and adding a new Renderer costs 1 class (not M shape variants). The abstraction (Shape) delegates rendering work to the implementor (Renderer). This is composition over inheritance applied to two axes of variation.
Shape + Renderer Bridge
Renderer is the Implementor interface. VectorRenderer and RasterRenderer are ConcreteImplementors. Shape is the Abstraction holding a Renderer. Circle and Square are RefinedAbstractions.
// Implementor interface
public interface Renderer {
void renderCircle(double radius);
void renderSquare(double side);
}
// Concrete Implementors
public class VectorRenderer implements Renderer {
@Override
public void renderCircle(double radius) {
System.out.printf("Drawing VECTOR circle with radius %.1f%n", radius);
}
@Override
public void renderSquare(double side) {
System.out.printf("Drawing VECTOR square with side %.1f%n", side);
}
}
public class RasterRenderer implements Renderer {
@Override
public void renderCircle(double radius) {
System.out.printf("Drawing RASTER circle (pixels) radius %.1f%n", radius);
}
@Override
public void renderSquare(double side) {
System.out.printf("Drawing RASTER square (pixels) side %.1f%n", side);
}
}
// Abstraction — holds reference to Implementor (the bridge)
public abstract class Shape {
protected final Renderer renderer; // bridge to implementation
protected Shape(Renderer renderer) {
this.renderer = renderer;
}
public abstract void draw();
public abstract void resize(double factor);
}
// Refined Abstractions
public class Circle extends Shape {
private double radius;
public Circle(Renderer renderer, double radius) {
super(renderer);
this.radius = radius;
}
@Override public void draw() { renderer.renderCircle(radius); }
@Override public void resize(double factor) { radius *= factor; }
}
public class Square extends Shape {
private double side;
public Square(Renderer renderer, double side) {
super(renderer);
this.side = side;
}
@Override public void draw() { renderer.renderSquare(side); }
@Override public void resize(double factor) { side *= factor; }
}
// Combining dimensions independently
Shape vectorCircle = new Circle(new VectorRenderer(), 5.0);
Shape rasterSquare = new Square(new RasterRenderer(), 3.0);
vectorCircle.draw(); // Drawing VECTOR circle with radius 5.0
rasterSquare.draw(); // Drawing RASTER square (pixels) side 3.0
// Switch renderer at runtime
Shape adaptedCircle = new Circle(new RasterRenderer(), 5.0);
adaptedCircle.draw(); // Drawing RASTER circle (pixels) radius 5.0Bridge vs Strategy
Bridge and Strategy look structurally identical (both use composition with an interface). Intent differs: Bridge separates an abstraction hierarchy from an implementation hierarchy (design-time decision); Strategy swaps algorithms in a single class at runtime (behavioral decision). Bridge is for two varying dimensions; Strategy is for one varying algorithm.
// Strategy — one class, swappable algorithm (behavioral)
public class Sorter {
private SortStrategy strategy; // swapped at runtime
public void setStrategy(SortStrategy s) { this.strategy = s; }
public void sort(int[] arr) { strategy.sort(arr); }
}
// Bridge — two independent hierarchies (structural)
// Abstraction hierarchy: Report → SalesReport, InventoryReport
// Implementation hierarchy: ReportRenderer → PdfRenderer, ExcelRenderer
public abstract class Report {
protected final ReportRenderer renderer; // bridge — set at construction
protected Report(ReportRenderer renderer) { this.renderer = renderer; }
public abstract void generate();
}
// Adding a new Report type: just subclass Report (1 class)
// Adding a new Renderer type: just implement ReportRenderer (1 class)
// No matrix explosionKey Points to Remember
- 1Bridge prevents M×N class explosion when two independent dimensions vary.
- 2The abstraction holds a reference to the implementor — both sides can vary independently.
- 3Bridge differs from Strategy: Bridge is structural (design-time hierarchy split); Strategy is behavioral (runtime algorithm swap).
- 4Use Bridge when both the abstraction AND implementation need subclassing independently.
- 5JDBC is a Bridge: Java application (abstraction) calls DriverManager/Connection API; JDBC driver (implementor) implements for each DB vendor.
Interview Questions
Sign in to ask AriaWhat problem does Bridge solve that inheritance cannot?
What is the difference between Bridge and Strategy patterns?
Is JDBC an example of Bridge pattern? Explain.
When would you prefer Bridge over Decorator?
Ask Aria about Bridge Pattern
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.