What is the Bridge Pattern

The Bridge Pattern is a structural design pattern that decouples an abstraction from its implementation so that the two can evolve independently. It achieves this by placing the abstraction and its implementation in separate class hierarchies connected by composition rather than inheritance.

This pattern is particularly useful when both the abstraction and its implementation may change over time and should not tightly depend on each other.

Pattern Structure

The Bridge Pattern typically involves:

  • Abstraction: Defines the interface and holds a reference to the implementation object.
  • RefinedAbstraction: Extends the interface defined by Abstraction.
  • Implementor: Interface for implementation classes.
  • ConcreteImplementor: Concrete classes implementing the Implementor interface.

Bridge Pattern UML Diagram

Abstraction

+operation()

|

v

+--------------------------------------+

| RefinedAbstraction |

| +operation() |

+--------------------------------------+

|

v

Implementor ---------> ConcreteImplementorA

+operation_impl() +operation_impl()

ConcreteImplementorB

+operation_impl()



Implementation Example in Python

Suppose we want to render shapes using different rendering engines (vector vs raster). We separate the shape abstraction from the rendering implementation.

# Implementor
class Renderer:
    def render_circle(self, radius):
        pass

# ConcreteImplementors
class VectorRenderer(Renderer):
    def render_circle(self, radius):
        print(f"Drawing a circle of radius {radius} using vector graphics.")

class RasterRenderer(Renderer):
    def render_circle(self, radius):
        print(f"Drawing a circle of radius {radius} using raster graphics.")

# Abstraction
class Shape:
    def __init__(self, renderer: Renderer):
        self.renderer = renderer

    def draw(self):
        raise NotImplementedError

# Refined Abstraction
class Circle(Shape):
    def __init__(self, renderer: Renderer, radius: float):
        super().__init__(renderer)
        self.radius = radius

    def draw(self):
        self.renderer.render_circle(self.radius)

# Example usage
vector = VectorRenderer()
raster = RasterRenderer()

circle1 = Circle(vector, 5)
circle2 = Circle(raster, 10)

circle1.draw()
circle2.draw()

When to Use

Use the Bridge Pattern when:

  • You want to avoid a permanent binding between an abstraction and its implementation.
  • Both abstractions and implementations may need to be extended independently.
  • You want to switch implementations at runtime.
  • You face class explosion due to a combination of multiple dimensions (e.g., shapes × rendering methods).