Python Bridge Design Pattern

1. Definition

The Bridge Design Pattern decouples an abstraction from its implementation, allowing the two to vary independently. In other words, it splits the abstract interface from its concrete realization, so they can be changed separately.

2. Problem Statement

Suppose you have a product with different versions and also need to support different platforms for each version. If you try to extend such a system, you'll end up with a huge number of classes due to the combinations of product versions and platforms.

3. Solution

The Bridge pattern suggests moving the platform-specific code into a separate class hierarchy. After the separation, you have two sets of classes: the abstractions and the implementations. The abstraction contains high-level control code, whereas the implementation does the platform-specific work.

4. Real-World Use Cases

1. Device drivers where the driver interface is constant, but the implementation can vary.

2. GUI libraries where each OS provides a different implementation, but the interface remains consistent.

3. Remote controls for different devices.

5. Implementation Steps

1. Recognize the orthogonal dimensions in your domain.

2. Split the monolithic class into distinct classes.

3. Create an abstract base for the abstraction.

4. Create an abstract base for the implementation.

5. Implement concrete classes for the abstractions and implementations.

6. Implementation in Python

# Implementation base
class Implementation:
    def operation_implementation(self):
        pass
# Concrete Implementations
class ConcreteImplementationA(Implementation):
    def operation_implementation(self):
        return "ConcreteImplementationA"
class ConcreteImplementationB(Implementation):
    def operation_implementation(self):
        return "ConcreteImplementationB"
# Abstraction base
class Abstraction:
    def __init__(self, implementation):
        self._implementation = implementation
    def operation(self):
        return self._implementation.operation_implementation()
# Extended Abstraction
class ExtendedAbstraction(Abstraction):
    def operation(self):
        return f"Extended: {self._implementation.operation_implementation()}"
# Client Code
abstraction = Abstraction(ConcreteImplementationA())
print(abstraction.operation())
extended_abstraction = ExtendedAbstraction(ConcreteImplementationB())
print(extended_abstraction.operation())

Output:

ConcreteImplementationA
Extended: ConcreteImplementationB

Explanation:

1. Implementation is a base for the implementation hierarchy.

2. ConcreteImplementationA and ConcreteImplementationB are the platform-specific implementations.

3. Abstraction represents the high-level logic and works with an object of the Implementation.

4. ExtendedAbstraction is an example of extending the Abstraction base class.

5. The client code demonstrates how different abstractions can work with different implementations.

7. When to use?

The Bridge Pattern should be used when:

1. You want to avoid a permanent binding between an abstraction and 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.

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


Comments