Open In App

Bridge Method Design Pattern in Java

Last Updated : 05 Aug, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

The Bridge Design Pattern is a structural design pattern that decouples an abstraction from its implementation so that the two can vary independently. This pattern is useful when both the abstractions and their implementations should be extensible by subclassing. The Bridge pattern allows us to avoid a permanent binding between an abstraction and its implementation, enabling more flexibility in the design and maintenance of code.

What is a Bridge Method Design Pattern in Java?

In Java, the Bridge Design Pattern is used to separate an abstraction from its implementation, allowing both to evolve independently. This pattern involves an interface (or abstract class) that represents the abstraction and another interface (or abstract class) that represents the implementation. The abstraction contains a reference to the implementation, and the concrete classes that extend the abstraction can interact with the concrete implementations through this reference.

Components of Bridge Method Design Pattern in Java

Below are the components of the Bridge Method Design Pattern in Java:

Class-Diagram-of-Bridge-Design-Pattern-
Class Diagram of Bridge Design Pattern
  1. Abstraction: This is the interface or abstract class that defines the high-level control logic or the abstraction of the functionality. It holds a reference to an implementation object.
  2. RefinedAbstraction: This is a subclass of the Abstraction that refines or extends the abstraction's behavior. It leverages the implementation object to perform operations.
  3. Implementor: This is an interface or abstract class that defines the low-level operations that the Abstraction uses. The Implementor defines the basic methods that are required to be implemented by its concrete implementations.
  4. ConcreteImplementor: This is a concrete class that implements the Implementor interface. It provides the actual implementation of the operations defined by the Implementor.

Example Implementation of Bridge Method Design Pattern in Java

Below is the step by step implementation of Bridge Method Design Pattern in Java:

1. Define the Implementor Interface

Java
// Implementor interface
public interface Implementor {
    void operationImpl();
}

2. Concrete Implementations of the Implementor Interface

Java
// ConcreteImplementorA
public class ConcreteImplementorA implements Implementor {
    @Override
    public void operationImpl() {
        System.out.println("ConcreteImplementorA operation implementation.");
    }
}

// ConcreteImplementorB
public class ConcreteImplementorB implements Implementor {
    @Override
    public void operationImpl() {
        System.out.println("ConcreteImplementorB operation implementation.");
    }
}

3. Define the Abstraction

Java
// Abstraction
public abstract class Abstraction {
    protected Implementor implementor;

    public Abstraction(Implementor implementor) {
        this.implementor = implementor;
    }

    public abstract void operation();
}

4. Refined Abstraction

Java
// RefinedAbstraction
public class RefinedAbstraction extends Abstraction {
    public RefinedAbstraction(Implementor implementor) {
        super(implementor);
    }

    @Override
    public void operation() {
        System.out.print("RefinedAbstraction operation: ");
        implementor.operationImpl();
    }
}

5. Main Class to Demonstrate the Bridge Pattern

Java
// Client code
public class BridgePatternDemo {
    public static void main(String[] args) {
        Implementor implementorA = new ConcreteImplementorA();
        Abstraction abstractionA = new RefinedAbstraction(implementorA);
        abstractionA.operation();

        Implementor implementorB = new ConcreteImplementorB();
        Abstraction abstractionB = new RefinedAbstraction(implementorB);
        abstractionB.operation();
    }
}

Complete Code with UML Diagram

In this example, Abstraction refers to Implementor to delegate the implementation of the operation, allowing RefinedAbstraction and the concrete implementations (ConcreteImplementorA and ConcreteImplementorB) to evolve independently

Java
// Implementor interface
public interface Implementor {
    void operationImpl();
}

// ConcreteImplementorA
public class ConcreteImplementorA implements Implementor {
    @Override
    public void operationImpl() {
        System.out.println("ConcreteImplementorA operation implementation.");
    }
}

// ConcreteImplementorB
public class ConcreteImplementorB implements Implementor {
    @Override
    public void operationImpl() {
        System.out.println("ConcreteImplementorB operation implementation.");
    }
}

// Abstraction
public abstract class Abstraction {
    protected Implementor implementor;

    public Abstraction(Implementor implementor) {
        this.implementor = implementor;
    }

    public abstract void operation();
}

// RefinedAbstraction
public class RefinedAbstraction extends Abstraction {
    public RefinedAbstraction(Implementor implementor) {
        super(implementor);
    }

    @Override
    public void operation() {
        System.out.print("RefinedAbstraction operation: ");
        implementor.operationImpl();
    }
}

// Client code
public class BridgePatternDemo {
    public static void main(String[] args) {
        Implementor implementorA = new ConcreteImplementorA();
        Abstraction abstractionA = new RefinedAbstraction(implementorA);
        abstractionA.operation();

        Implementor implementorB = new ConcreteImplementorB();
        Abstraction abstractionB = new RefinedAbstraction(implementorB);
        abstractionB.operation();
    }
}

Output

Output
RefinedAbstraction operation: ConcreteImplementorA operation implementation.
RefinedAbstraction operation: ConcreteImplementorB operation implementation.

Explanation of the above code:

  • Abstraction: Represents the abstraction side of the bridge. It defines an interface and maintains a reference to an Implementor.
  • RefinedAbstraction: Extends the Abstraction class. It implements the operation() method which delegates the call to the operationImpl() method of the Implementor.
  • Implementor: Defines the interface for implementation classes. It has a method operationImpl() which needs to be implemented by the concrete implementors.
  • ConcreteImplementorA and ConcreteImplementorB: These are the concrete implementations of the Implementor interface. They provide specific implementations of the operationImpl() method.

Advantages of Bridge Method Design Pattern in Java

Below are the advantages of bridge method design pattern in Java:

  • Decoupling Abstraction and Implementation: The pattern decouples the abstraction from its implementation, allowing them to be developed and modified independently.
  • Improved Extensibility: It is easier to extend both abstraction and implementation hierarchies independently.
  • Enhanced Flexibility: The pattern allows changing the implementation without modifying the abstraction and vice versa.
  • Simplified Code Maintenance: By separating the concerns, the code becomes more maintainable and understandable.

When to Use Bridge Method Design Pattern in Java

  • When you need to avoid a permanent binding between an abstraction and its implementation.
  • When both the abstraction and implementation should be extensible through subclassing.
  • When changes in the implementation of an abstraction should not impact the clients.
  • When you want to share an implementation among multiple objects and hide implementation details from the clients.

When Not to Use Bridge Method Design Pattern in Java

  • When there is no clear distinction between abstraction and implementation, making the pattern unnecessary.
  • When the abstraction and implementation are not expected to change independently or extend significantly.
  • When the added complexity of separating abstraction and implementation does not provide significant benefits.

Conclusion

The Bridge Design Pattern is a powerful tool in Java for decoupling an abstraction from its implementation, providing flexibility and ease of maintenance. It is particularly useful in situations where both the abstraction and implementation are expected to evolve. However, it's essential to assess the complexity and requirements of the project to determine if this pattern is the best fit. Understanding and applying the Bridge pattern effectively can lead to more robust and adaptable software designs.


Next Article

Similar Reads