# BridgeA intermediate-level guide to Bridge: before-and-after java code and diagrams for a CS student.

## The Class Explosion Problem

Imagine you are building a graphics engine. Initially, you only have two shapes: Circles and Squares. You implement them using inheritance to handle different colors, creating `RedCircle` and `BlueCircle`. 

The problem arises when your requirements grow. If you add a third color, Green, you must create `GreenCircle` and `GreenSquare`. If you then decide to support a new shape, Triangle, the explosion begins: you need `RedTriangle`, `BlueTriangle`, and `GreenTriangle`. 

As you can see in this diagram, adding just one new dimension (like a new color or a new shape type) forces you to multiply your existing classes. This is a "class explosion" caused by multi-dimensional inheritance.

```mermaid
classDiagram
    class Shape {
        <<abstract>>
        +draw() void
    }
    class RedCircle {
        +draw() void
    }
    class BlueCircle {
        +draw() void
    }
    class RedSquare {
        +draw() void
    }
    class BlueSquare {
        +draw() void
    }
    Shape <|-- RedCircle
    Shape <|-- BlueCircle
    Shape <|-- RedSquare
    Shape <|-- BlueSquare
```

```java
// Problem: Class explosion due to multi-dimensional inheritance.
// To add a new color OR a new shape, we must create multiple new subclasses.

abstract class Shape {
    abstract void draw();
}

class RedCircle extends Shape {
    @Override
    void draw() {
        System.out.println("Drawing a red circle");
    }
}

class BlueCircle extends Shape {
    @Override
    void draw() {
        System.out.println("Drawing a blue circle");
    }
}

class RedSquare extends Shape {
    @Override
    void draw() {
        System.out.println("Drawing a red square");
    }
}

class BlueSquare extends Shape {
    @Override
    void draw() {
        System.out.println("Drawing a blue square");
    }
}
```

## Separating Abstraction from Implementation

The Bridge pattern solves this by replacing inheritance with composition. Instead of trying to define a class that is both a "Circle" and "Red," we split the problem into two separate hierarchies:

1.  **Abstraction:** The high-level control logic (the `Shape` itself).
2.  **Implementation:** The platform-specific or detail-oriented work (the `Color`).

Instead of inheriting color properties, a `Shape` holds a private reference to a `Color` object. When the `Shape` needs to perform an action involving color, it delegates that task to its `color` reference. This is known as **Delegation**.

By using this "bridge" between the two hierarchies, adding a new shape only requires one new class, and adding a new color only requires one new class. The growth becomes linear rather than exponential.

```mermaid
classDiagram
    class Shape {
        <<abstract>>
        #color: Color
        +draw() void
    }
    class Circle {
        +draw() void
    }
    class Square {
        +draw() void
    }
    class Color {
        <<interface>>
        +apply() void
    }
    class RedColor {
        +apply() void
    }
    class BlueColor {
        +apply() void
    }

    Shape <|-- Circle
    Shape <|-- Square
    Shape o-- Color : color
    Color <|.. RedColor
    Color <|.. BlueColor
```

To understand how these objects interact at runtime, look at how a `Circle` uses its delegated `color` object to fulfill a request.

```mermaid
sequenceDiagram
    participant S as Circle
    participant C as RedColor
    S->>C: apply()
    Note over C: Prints "red"
    C-->>S: done
```

```java
// Solution: Bridge pattern.
// We separate the Abstraction (Shape) from its Implementation (Color).

interface Color {
    void apply();
}

class RedColor implements Color {
    @Override
    public void apply() {
        System.out.println("red");
    }
}

class BlueColor implements Color {
    @Override
    public void apply() {
        System.out.println("blue");
    }
}

abstract class Shape {
    protected final Color color;

    protected Shape(Color color) {
        this.color = color;
    }

    abstract void draw();
}

class Circle extends Shape {
    Circle(Color color) { super(color); }

    @Override
    void draw() {
        System.out.print("Drawing a ");
        color.apply();
        System.out.println(" circle");
    }
}

class Square extends Shape {
    Square(Color color) { super(color); }

    @Override
    void draw() {
        System.out.print("Drawing a ");
        color.apply();
        System.out.println(" square");
    }
}
```

## Technical Breakdown: The Roles in Bridge

To implement this pattern successfully, you need to understand the four distinct roles:

*   **Abstraction:** Defines the interface for the client (e.g., `Shape`). It maintains a reference to an object of type Implementor.
*   **Refined Abstraction:** Extends the abstraction and provides specialized versions of the high-level logic (e.g., `Circle` and `Square`).
*   **Implementor:** Defines the interface for implementation classes (e.g., `Color`). This interface is separate from the abstraction so they can vary independently.
*   **Concrete Implementors:** The actual platform-specific or detail-oriented implementations (e.g., `RedColor` and `BlueColor`).

### Bridge vs. Strategy
While both use composition to delegate work, they serve different purposes. **Bridge** is a structural pattern used upfront during design to prevent a permanent hierarchy explosion. It separates two dimensions of a class (what it does vs. how it does the details). **Strategy** is a behavioral pattern typically used at runtime to swap out algorithms for a specific task.

## When to Use It, and When Not To

The Bridge pattern is an investment in future flexibility. 

**Use it when:**
*   You want to avoid a permanent binding between an abstraction and its implementation.
*   You have two dimensions of variation (like `Shape` and `Color`, or `RemoteControl` and `Device`) that are likely to grow independently.
*   You want to share an implementation among multiple objects.

**Avoid it when:**
*   Your class hierarchy is simple and unlikely to grow in multiple directions. Applying Bridge to a single-dimension hierarchy adds unnecessary complexity through extra interfaces and delegation.
*   The performance overhead of the extra method call (the delegation hop) is unacceptable for your specific high-frequency loop.

## Takeaways

*   Bridge uses composition to separate an object's interface from its implementation, preventing class explosion.
*   It turns exponential growth in subclasses into linear growth across two independent hierarchies.
*   Use it when you anticipate multiple axes of change; avoid it if the complexity of the pattern outweighs the benefits of the abstraction.

## Usage

**Using the Bridge to compose shape and color independently**

```java
Shape circle = new Circle(new RedColor());
circle.draw(); // Drawing a red circle
```
