# Bridge Pattern

> Decouple an abstraction from its implementation so that the two can vary independently.

## Problem

You have shapes (Circle, Square) and renderers (Vector, Raster). Without Bridge you'd need CircleVector, CircleRaster, SquareVector, SquareRaster — an N×M class explosion. Adding a new shape or renderer forces changes across all combinations.

## Solution

Separate the two dimensions into independent hierarchies connected by composition. `Shape` holds a reference to a `Renderer`, delegating the rendering concern.

```
┌───────────────────┐          ┌──────────────────┐
│   Shape (abstract) │─────────▶│ Renderer (intf)  │
│   + draw()         │          │ + render_circle()│
│   + renderer       │          │ + render_square()│
└──────┬────────────┘          └──────┬───────────┘
       │                              │
  ┌────┴────┐                  ┌──────┴──────┐
  │ Circle  │                  │VectorRender │
  │ Square  │                  │RasterRender │
  └─────────┘                  └─────────────┘
```

## When to Use

- You have two (or more) orthogonal dimensions of variation.
- You want to avoid a combinatorial explosion of subclasses.
- You need to switch implementations at runtime.

## When to Avoid

- There is only one dimension of variation — simpler polymorphism suffices.
- The abstraction and implementation are unlikely to change independently.
- The added indirection makes the design harder to understand for a simple case.

## Pseudocode

```
interface Renderer:
    method render_circle(radius)
    method render_square(side)

class VectorRenderer implements Renderer:
    method render_circle(radius):
        output "Drawing circle [vector] r=" + radius
    method render_square(side):
        output "Drawing square [vector] s=" + side

class RasterRenderer implements Renderer:
    method render_circle(radius):
        output "Drawing circle [raster] r=" + radius
    method render_square(side):
        output "Drawing square [raster] s=" + side

abstract class Shape:
    field renderer: Renderer
    constructor(renderer):
        this.renderer = renderer
    abstract method draw()

class Circle extends Shape:
    field radius
    constructor(renderer, radius):
        super(renderer)
        this.radius = radius
    method draw():
        renderer.render_circle(radius)

class Square extends Shape:
    field side
    constructor(renderer, side):
        super(renderer)
        this.side = side
    method draw():
        renderer.render_square(side)

// Usage
vector = new VectorRenderer()
raster = new RasterRenderer()
shapes = [Circle(vector, 5), Square(raster, 4), Circle(raster, 3)]
for s in shapes:
    s.draw()
```

## Python

```python
from abc import ABC, abstractmethod


class Renderer(ABC):
    """Implementation interface."""

    @abstractmethod
    def render_circle(self, radius: float) -> None: ...

    @abstractmethod
    def render_square(self, side: float) -> None: ...


class VectorRenderer(Renderer):
    def render_circle(self, radius: float) -> None:
        print(f"Drawing circle [vector] r={radius}")

    def render_square(self, side: float) -> None:
        print(f"Drawing square [vector] s={side}")


class RasterRenderer(Renderer):
    def render_circle(self, radius: float) -> None:
        print(f"Drawing circle [raster] r={radius}")

    def render_square(self, side: float) -> None:
        print(f"Drawing square [raster] s={side}")


class Shape(ABC):
    """Abstraction that holds a reference to a Renderer."""

    def __init__(self, renderer: Renderer) -> None:
        self.renderer = renderer

    @abstractmethod
    def draw(self) -> None: ...


class Circle(Shape):
    def __init__(self, renderer: Renderer, radius: float) -> None:
        super().__init__(renderer)
        self.radius = radius

    def draw(self) -> None:
        self.renderer.render_circle(self.radius)


class Square(Shape):
    def __init__(self, renderer: Renderer, side: float) -> None:
        super().__init__(renderer)
        self.side = side

    def draw(self) -> None:
        self.renderer.render_square(self.side)


if __name__ == "__main__":
    vector = VectorRenderer()
    raster = RasterRenderer()

    shapes: list[Shape] = [
        Circle(vector, 5),
        Square(raster, 4),
        Circle(raster, 3),
        Square(vector, 7),
    ]

    for shape in shapes:
        shape.draw()
```

**Output:**
```
Drawing circle [vector] r=5
Drawing square [raster] s=4
Drawing circle [raster] r=3
Drawing square [vector] s=7
```

## Go

```go
package main

import "fmt"

// --- Implementation interface ---

type Renderer interface {
	RenderCircle(radius float64)
	RenderSquare(side float64)
}

type VectorRenderer struct{}

func (v *VectorRenderer) RenderCircle(radius float64) {
	fmt.Printf("Drawing circle [vector] r=%.0f\n", radius)
}
func (v *VectorRenderer) RenderSquare(side float64) {
	fmt.Printf("Drawing square [vector] s=%.0f\n", side)
}

type RasterRenderer struct{}

func (r *RasterRenderer) RenderCircle(radius float64) {
	fmt.Printf("Drawing circle [raster] r=%.0f\n", radius)
}
func (r *RasterRenderer) RenderSquare(side float64) {
	fmt.Printf("Drawing square [raster] s=%.0f\n", side)
}

// --- Abstraction ---

type Shape interface {
	Draw()
}

type Circle struct {
	renderer Renderer
	radius   float64
}

func NewCircle(r Renderer, radius float64) *Circle {
	return &Circle{renderer: r, radius: radius}
}
func (c *Circle) Draw() { c.renderer.RenderCircle(c.radius) }

type Square struct {
	renderer Renderer
	side     float64
}

func NewSquare(r Renderer, side float64) *Square {
	return &Square{renderer: r, side: side}
}
func (s *Square) Draw() { s.renderer.RenderSquare(s.side) }

func main() {
	vector := &VectorRenderer{}
	raster := &RasterRenderer{}

	shapes := []Shape{
		NewCircle(vector, 5),
		NewSquare(raster, 4),
		NewCircle(raster, 3),
		NewSquare(vector, 7),
	}

	for _, s := range shapes {
		s.Draw()
	}
}
```

**Output:**
```
Drawing circle [vector] r=5
Drawing square [raster] s=4
Drawing circle [raster] r=3
Drawing square [vector] s=7
```

## JavaScript

```javascript
// --- Implementation ---

class VectorRenderer {
  renderCircle(radius) {
    console.log(`Drawing circle [vector] r=${radius}`);
  }
  renderSquare(side) {
    console.log(`Drawing square [vector] s=${side}`);
  }
}

class RasterRenderer {
  renderCircle(radius) {
    console.log(`Drawing circle [raster] r=${radius}`);
  }
  renderSquare(side) {
    console.log(`Drawing square [raster] s=${side}`);
  }
}

// --- Abstraction ---

class Circle {
  constructor(renderer, radius) {
    this.renderer = renderer;
    this.radius = radius;
  }
  draw() {
    this.renderer.renderCircle(this.radius);
  }
}

class Square {
  constructor(renderer, side) {
    this.renderer = renderer;
    this.side = side;
  }
  draw() {
    this.renderer.renderSquare(this.side);
  }
}

// --- Main ---
const vector = new VectorRenderer();
const raster = new RasterRenderer();

const shapes = [
  new Circle(vector, 5),
  new Square(raster, 4),
  new Circle(raster, 3),
  new Square(vector, 7),
];

shapes.forEach((s) => s.draw());
```

**Output:**
```
Drawing circle [vector] r=5
Drawing square [raster] s=4
Drawing circle [raster] r=3
Drawing square [vector] s=7
```

## Related Patterns

- **Adapter** — adapter makes incompatible interfaces work together after the fact; bridge is designed upfront to let abstraction and implementation vary independently.
- **Strategy** — strategy changes the algorithm at runtime; bridge separates an abstraction from its implementation as a structural concern.
- **Abstract Factory** — abstract factory can create and configure a bridge, producing the right abstraction/implementation pair.
