Design Patterns Bridge
The Bridge pattern splits one large class into two separate hierarchies: an abstraction and an implementation. A reference links them, and each side grows independently. Developers avoid a flood of combined subclasses.
The Real-World Analogy
Consider remote controls and televisions. A basic remote and an advanced remote both work with any brand of TV. Nobody builds a separate remote for every remote-and-TV pair. The remote holds a link to a TV, and the two sides evolve on their own.
Problem Without Bridge
Shape ├── RedCircle ├── BlueCircle ├── RedSquare ├── BlueSquare ├── RedTriangle └── BlueTriangle 3 shapes × 2 colors = 6 classes. Add green → 9 classes. Add a shape → 12 classes.
The class count multiplies with every new option. Maintenance becomes painful quickly.
Solution With Bridge
Abstraction side Implementation side ┌──────────────┐ has-a ┌──────────────┐ │ Shape │ ─────────────▶ │ Color │ └──────▲───────┘ └──────▲───────┘ ┌───┴────┐ ┌───┴────┐ Circle Square Red Blue 3 shapes + 2 colors = 5 classes. Add green → 6 classes.
Addition replaces multiplication. Each new color or shape costs exactly one class.
Structure
┌────────────────────────┐ ┌─────────────────────────┐
│ Abstraction │ │ «interface» │
│ - impl: Implementor │──────▶│ Implementor │
│ + operation() │ │ + operationImpl() │
└──────────▲─────────────┘ └────────────▲────────────┘
│ │
┌──────────┴─────────────┐ ┌────────────┴────────────┐
│ RefinedAbstraction │ │ ConcreteImplementor │
└────────────────────────┘ └─────────────────────────┘
Roles
- Abstraction: the high-level control layer that holds a reference.
- Implementor: the interface for low-level work.
- Refined Abstraction: a variant of the control layer.
- Concrete Implementor: one real version of the low-level work.
Code Example
interface Color { String fill(); }
class Red implements Color { public String fill() { return "red"; } }
class Blue implements Color { public String fill() { return "blue"; } }
abstract class Shape {
protected Color color; // the bridge
Shape(Color color) { this.color = color; }
abstract void draw();
}
class Circle extends Shape {
Circle(Color color) { super(color); }
void draw() { print("Circle filled with " + color.fill()); }
}
class Square extends Shape {
Square(Color color) { super(color); }
void draw() { print("Square filled with " + color.fill()); }
}
new Circle(new Red()).draw(); // Circle filled with red
new Square(new Blue()).draw(); // Square filled with blueReal Projects Using Bridge
| Scenario | Abstraction | Implementation |
|---|---|---|
| Notification app | Alert types: urgent, normal | Channels: email, SMS, push |
| Graphics tool | Shapes | Rendering engines |
| Device apps | Remote types | Device brands |
Bridge Versus Adapter
Adapter fixes a mismatch after two classes already exist. Bridge plans the split from the start. Designers pick Bridge during early planning and Adapter during integration.
Advantages and Disadvantages
| Advantages | Disadvantages |
|---|---|
| Two hierarchies grow independently | More upfront design effort |
| Fewer classes overall | Extra indirection for small programs |
| Runtime swapping of implementations | Beginners need time to see the split |
Step-by-Step Walkthrough
Follow the shape example. The client picks a Red color object and a Circle shape, and joins them through the Circle constructor. Inside the Circle, a protected field stores the color. Calling draw() asks the color for its fill name and prints the combined result.
A new color named Green needs one small class that implements Color. Every existing shape accepts it instantly, because shapes know only the Color interface. A new shape named Triangle needs one class that extends Shape. Every existing color works with it immediately.
Spotting the Need for Bridge
Look at class names in a project. Names that join two ideas, such as RedCircle, BlueSquare, or SmsUrgentAlert, signal two dimensions mixed in one hierarchy. Split the dimensions, and the multiplying names vanish.
Plain-Words Summary
Think of Bridge as a plug-and-socket design for classes. Each side defines a clear connector, and any matching part snaps in. Teams that adopt the habit stop fearing new requirements, because a new option means one new class instead of a tangle of edits across the hierarchy. Beginners often grasp the idea fastest by drawing two columns of boxes and linking them with a single arrow.
Key Takeaways
- Bridge separates "what" from "how" using composition.
- It prevents the class explosion from combining two changing dimensions.
- Implementations swap at runtime through the reference.
- Plan Bridge early, while Adapter patches mismatches later.
