Bridge Pattern — Core Concepts

The problem: combinatorial explosion

Imagine a notification system. You have notification types (alert, reminder, report) and delivery channels (email, SMS, push notification). Without careful design, you end up with classes like EmailAlert, SMSAlert, PushAlert, EmailReminder, SMSReminder, PushReminder… That’s types × channels classes, and every new type or channel multiplies the total.

The Bridge Pattern solves this by separating the two dimensions: what the notification says (abstraction) from how it gets delivered (implementation). Each side evolves independently.

How the bridge works

The pattern has two hierarchies connected by composition:

  • Abstraction: Defines the high-level interface and holds a reference to an implementation
  • Implementation: Defines the low-level operations the abstraction delegates to

The abstraction doesn’t inherit from the implementation. It contains one. This is the “bridge” — a reference that connects two independent hierarchies.

The two dimensions

Think of it as a matrix:

EmailSMSPush
Alert
Reminder
Report

Without a bridge: 9 classes (one per cell). With a bridge: 3 abstraction classes + 3 implementation classes = 6 total. Add a new channel? Just 1 new class, not 3.

When to use the bridge

  • You have two independent dimensions that both need to vary
  • You want to avoid a “class explosion” from combining variations
  • You need to swap implementations at runtime (e.g., switch from SQL to NoSQL without changing business logic)
  • Platform-specific code needs to be isolated from platform-independent logic

When to skip it

  • Only one dimension varies — use strategy or simple polymorphism instead
  • The abstraction and implementation are tightly coupled by nature and unlikely to change independently
  • The added indirection isn’t worth the complexity for a small codebase

Bridge vs strategy

These patterns look similar because both use composition to delegate behavior. The difference is scope:

AspectBridgeStrategy
ScaleTwo full hierarchiesOne interchangeable behavior
PurposeSeparate two orthogonal dimensionsSwap one algorithm
ComplexityHigher — two parallel class treesLower — one interface, multiple implementations

If you have one thing that varies (sorting algorithm, compression method), use strategy. If you have two things that vary independently (shape + renderer, notification + channel), use bridge.

Common misconception

“Bridge is just dependency injection.” Dependency injection is a technique — you pass a dependency from outside. Bridge is a pattern — it specifically addresses two parallel hierarchies that need to evolve independently. Bridge uses dependency injection, but not all dependency injection is a bridge.

The one thing to remember: Bridge Pattern prevents class explosion by keeping two independent dimensions of variation in separate hierarchies connected by composition — add to either side without multiplying the other.

pythondesign-patternsoop

See Also

  • Python Adapter Pattern How Python's Adapter Pattern works like a travel power plug — making incompatible things work together.
  • Python Builder Pattern Why building complex Python objects step by step beats cramming everything into one giant constructor.
  • Python Composite Pattern How the Composite Pattern lets you treat a group of things the same way you'd treat a single thing in Python.
  • Python Facade Pattern How the Facade Pattern gives you one simple button instead of a confusing control panel in Python.
  • Python Flyweight Pattern How the Flyweight Pattern saves memory by sharing common data instead of copying it thousands of times.