Middle+
What is the 'Bridge' design pattern?
sobes.tech AI
Answer from AI
The "Bridge" pattern is a structural design pattern that separates abstraction and implementation, allowing them to vary independently.
Key features:
- Separation: Separates an abstract class or interface from its concrete implementation.
- Flexibility: Allows dynamically linking different implementations with the same abstraction.
- Reducing complexity: Prevents the growth of class hierarchies that arise with inheritance.
Structure:
- Abstraction: Defines the interface part of the class (client interface) and contains a reference to the implementation.
- Refined Abstraction: Extends the abstraction, adding or modifying behavior.
- Implementor: Defines the interface for implementation classes. Not necessarily one-to-one with the abstraction.
- Concrete Implementor: Implements the implementor interface.
Example:
Suppose there are shapes (circle, square) and renderers (draw on screen, export to file). Without Bridge, you'd create classes like ScreenCircle, FileCircle, ScreenSquare, FileSquare. With Bridge, you can have Circle and Square (abstractions) and ScreenRenderer and FileRenderer (concrete implementations), linked via an interface.
# Implementor
class DrawingAPI:
def draw_circle(self, x, y, radius):
pass
# Concrete Implementor A
class DrawingAPI1(DrawingAPI):
def draw_circle(self, x, y, radius):
print(f"API1 drawing circle at ({x}, {y}) with radius {radius}")
# Concrete Implementor B
class DrawingAPI2(DrawingAPI):
def draw_circle(self, x, y, radius):
print(f"API2 drawing circle at ({x}, {y}) with radius {radius}")
# Abstraction
class Shape:
def __init__(self, drawing_api):
self._drawing_api = drawing_api
def draw(self):
pass
def resize_by_percentage(self, percent):
pass
# Refined Abstraction
class CircleShape(Shape):
def __init__(self, x, y, radius, drawing_api):
super().__init__(drawing_api)
self._x = x
self._y = y
self._radius = radius
def draw(self):
self._drawing_api.draw_circle(self._x, self._y, self._radius)
def resize_by_percentage(self, percent):
self._radius *= (1 + percent / 100)
# Client code
# api1 = DrawingAPI1()
# api2 = DrawingAPI2()
# circle1 = CircleShape(1, 2, 3, api1)
# circle2 = CircleShape(5, 7, 11, api2)
# circle1.draw()
# circle2.draw()
This pattern is useful when you want to avoid tight coupling between abstraction and implementation, allowing them to evolve independently.