What is Bridge pattern?

The Bridge pattern is a structural design pattern that decouples an abstraction from its implementation, allowing them to vary independently. It achieves this by encapsulating the abstraction and implementation into separate class hierarchies and providing a bridge between them.

The Bridge pattern is useful when you have multiple variations of an abstraction and multiple implementations, and you want to avoid the explosion of subclasses that would result from coupling all the variations with all the implementations. It promotes flexibility, extensibility, and maintainability by allowing you to add new abstractions or implementations without modifying the existing code.

Key components of the Bridge pattern:

  1. Abstraction: This is the high-level abstraction that defines the interface or functionality that the client code interacts with. It maintains a reference to an object of the implementation hierarchy and delegates the implementation-specific operations to that object.
  2. Refined Abstraction: Refined abstractions are subclasses of the abstraction that provide additional or specialized functionality. They can extend the abstraction with new methods or override existing ones.
  3. Implementor: The implementor is an interface or abstract class that defines the operations that can be performed on the implementation hierarchy. The abstraction holds a reference to an object of the implementor hierarchy and delegates the implementation-specific operations to that object.
  4. Concrete Implementor: Concrete implementors are subclasses of the implementor that provide specific implementations of the operations defined in the implementor interface or abstract class. There can be multiple concrete implementors representing different variations of the implementation.

Benefits and use cases of the Bridge pattern:

  1. Decoupling of abstraction and implementation: The Bridge pattern allows the abstraction and implementation to vary independently. Changes in the abstraction or implementation do not affect each other, providing flexibility and avoiding the need for extensive class hierarchies.
  2. Separation of concerns: The Bridge pattern promotes separation of concerns by separating the higher-level abstraction from the lower-level implementation details. This helps manage complexity and allows for easier maintenance and modification of the code.
  3. Flexibility and extensibility: By decoupling the abstraction and implementation, the Bridge pattern enables the addition of new abstractions or implementations without modifying the existing code. New abstractions or implementations can be introduced independently, promoting flexibility and extensibility.
  4. Enhanced runtime binding: The Bridge pattern supports runtime binding between the abstraction and the implementation. The concrete implementation can be determined dynamically at runtime, allowing for dynamic selection or change of the implementation based on the context or configuration.
  5. Multiple platform support: The Bridge pattern is often used in scenarios where a single abstraction needs to support multiple platforms or environments. By defining a separate hierarchy for the implementation, the Bridge pattern allows the abstraction to be easily adapted to different platforms or environments.

Example of the Bridge pattern in Java:

// Implementor interface
public interface MessageSender {
    void sendMessage(String message);
}

// Concrete implementor 1
public class EmailSender implements MessageSender {
    public void sendMessage(String message) {
        System.out.println("Sending email message: " + message);
    }
}

// Concrete implementor 2
public class SmsSender implements MessageSender {
    public void sendMessage(String message) {
        System.out.println("Sending SMS message: " + message);
    }
}

// Abstraction
public abstract class Message {
    protected MessageSender sender;

    public Message(MessageSender sender) {
        this.sender = sender;
    }

    public abstract void send();
}

// Refined abstraction 1
public class TextMessage extends Message {
    public TextMessage(MessageSender sender) {
        super(sender);
    }

    public void send() {
        String message = "This is a text message.";
        sender.sendMessage(message);
    }
}

// Refined abstraction 2
public class EmailMessage extends Message {
    public EmailMessage(MessageSender sender) {
        super(sender);
    }

    public void send() {
        String message = "This is an email message.";
        sender.sendMessage(message);
    }
}

// Usage:
MessageSender emailSender = new EmailSender();
Message emailMessage = new EmailMessage(emailSender);
emailMessage.send();

MessageSender smsSender = new SmsSender();
Message smsMessage = new TextMessage(smsSender);
smsMessage.send();

In the above example, the Bridge pattern is used to separate the message abstraction from its sender implementation. The MessageSender interface represents the implementor interface, defining the sendMessage() method for sending messages.

The EmailSender and SmsSender classes are concrete implementors that provide specific implementations of the sendMessage() method for sending emails and SMS messages, respectively.

The Message class is the abstraction that holds a reference to a MessageSender object and delegates the message sending operation to the concrete sender implementation.

The TextMessage and EmailMessage classes are refined abstractions that inherit from the Message class and provide specialized functionality for sending text messages and email messages.

In the usage example, instances of the concrete implementors (EmailSender and SmsSender) are passed to the concrete abstractions (EmailMessage and TextMessage). The abstractions delegate the message sending operation to the corresponding implementor’s sendMessage() method.

By decoupling the message abstraction from its sender implementation, the Bridge pattern allows for flexible composition of different message senders with different types of messages. New senders or messages can be easily added without modifying the existing code, promoting flexibility and extensibility.

error: Content is protected !!