Bridge Design Pattern in Java

1. Definition

The Bridge Design Pattern decouples an abstraction from its implementation, allowing both to evolve independently. It promotes the principle that abstraction and implementation should be extendable separately without affecting each other.

2. Problem Statement

Imagine you have a set of shapes like Circle and Square, and you want to give each shape different colors. Without the Bridge pattern, you might have classes like RedCircle, BlueCircle, RedSquare, BlueSquare, etc. If you introduce more attributes like shading, this approach becomes cumbersome and doesn't scale.

3. Solution

The Bridge Pattern tackles this by separating the shape (abstraction) from its color (implementation). Now, each shape can have any color, making it easier to introduce new shapes or colors without changing existing code.

4. Real-World Use Cases

1. Remote controls and devices: Different remotes (abstraction) can operate various devices (implementation) without each remote having a separate version for every device.

2. Device drivers: OS interfaces (abstraction) can communicate with hardware devices (implementation) via drivers without needing to know device-specific details.

5. Implementation Steps

1. Define the abstraction (e.g., Shape).

2. Define the implementor interface (e.g., Color).

3. Create refined abstractions for each concrete class in the abstraction hierarchy (e.g., Circle, Square).

4. Implement the implementor interface for each concrete class in the implementor hierarchy (e.g., Red, Blue).

5. Link the refined abstractions to the correct implementor.

6. Implementation

// Step 1: Create the Color interface (Implementor)
interface Color {
    void applyColor();
}

// Step 2: Implement the Color interface
class Red implements Color {
    public void applyColor() {
        System.out.println("Applying red color");
    }
}

class Blue implements Color {
    public void applyColor() {
        System.out.println("Applying blue color");
    }
}

// Step 3: Create the Shape abstraction
abstract class Shape {
    protected Color color;

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

    abstract void draw();
}

// Step 4: Implement the Shape abstraction
class Circle extends Shape {
    public Circle(Color color) {
        super(color);
    }

    public void draw() {
        System.out.print("Drawing Circle in ");
        color.applyColor();
    }
}

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

    public void draw() {
        System.out.print("Drawing Square in ");
        color.applyColor();
    }
}

// Step 5: Demonstrate the Bridge Design Pattern
public class BridgePatternDemo {
    public static void main(String[] args) {
        Shape redCircle = new Circle(new Red());
        Shape blueSquare = new Square(new Blue());

        redCircle.draw();
        blueSquare.draw();
    }
}

Output:

Drawing Circle in Applying red color
Drawing Square in Applying blue color

Explanation

The Bridge Pattern separates the Circle and Square (shapes) from their colors (Red and Blue). Each shape can independently vary from its color. By introducing this separation, it becomes easier to add new shapes or colors without modifying the existing hierarchies.

7. When to use?

Use the Bridge Pattern when:

1. You want to avoid permanently binding an abstraction to its implementation.

2. Both the abstractions and their implementations should be extensible by subclassing.

3. Changes in the implementation of an abstraction should have no impact on clients; that is, their code should not have to be recompiled.

4. You want to hide the implementation of an abstraction completely from clients.

By separating concerns, the Bridge Design Pattern ensures that modularization of code leads to easier maintenance and scalability.


Comments