9.7. Bridge
EN: Bridge
PL: Most
Type: object
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 involves an interface which acts as a bridge which makes the functionality of concrete classes independent from interface implementer classes.
Here's a simple example of the Bridge pattern in Python:
>>> class Abstraction:
... def __init__(self, implementation):
... self._implementation = implementation
...
... def operation(self):
... return (f"Abstraction: Base operation with:\n"
... f"{self._implementation.operation_implementation()}")
...
>>> class Implementation:
... def operation_implementation(self):
... pass
...
>>> class ConcreteImplementationA(Implementation):
... def operation_implementation(self):
... return "ConcreteImplementationA: Here's the result on the platform A."
...
>>> class ConcreteImplementationB(Implementation):
... def operation_implementation(self):
... return "ConcreteImplementationB: Here's the result on the platform B."
...
>>> implementation = ConcreteImplementationA()
>>> abstraction = Abstraction(implementation)
>>> print(abstraction.operation())
Abstraction: Base operation with:
ConcreteImplementationA: Here's the result on the platform A.
>>> implementation = ConcreteImplementationB()
>>> abstraction = Abstraction(implementation)
>>> print(abstraction.operation())
Abstraction: Base operation with:
ConcreteImplementationB: Here's the result on the platform B.
In this example, Abstraction is a class that maintains a reference to an object of the Implementation class. It defines an interface and maintains the link between it and the objects of the Implementation class. ConcreteImplementationA and ConcreteImplementationB are concrete classes that implement the Implementation interface. The operation method in the Abstraction class calls the operation_implementation method in the Implementation class.
9.7.1. Pattern
Nested hierarchies of classes
9.7.2. Problem
Every time you want to add new manufacturers remote control, you need to add two classes of
ManufacturerRemoteControl
andManufacturerAdvancedRemoteControl
If you add new another type of remote control, such as
MovieRemoteControl
you now has to implement three classes
Basic Remote Control (turnOn, turnOff)
Advanced Remote Control (setChannel)
Movie Remote Control (play, pause, rewind)
RemoteControl
SonyRemoteControl
SamsungRemoteControl
AdvancedRemoteControl
SonyAdvancedRemoteControl
SamsungAdvancedRemoteControl
from abc import ABC, abstractmethod
class RemoteControl(ABC):
@abstractmethod
def turn_on(self) -> None:
pass
@abstractmethod
def turn_off(self) -> None:
pass
class AdvancedRemoteControl(RemoteControl, ABC):
@abstractmethod
def set_channel(self, number: int) -> None:
pass
class SonyRemoteControl(RemoteControl):
def turn_off(self) -> None:
print('Sony turn off')
def turn_on(self) -> None:
print('Sony turn on')
class SonyAdvancedRemoteControl(AdvancedRemoteControl):
def set_channel(self, number: int) -> None:
print('Sony set channel')
def turn_off(self) -> None:
print('Sony turn off')
def turn_on(self) -> None:
print('Sony turn on')
9.7.3. Solution
Hierarchy grows in two different directions
We can split complex hierarchy into two hierarchies which grows independently
from abc import ABC, abstractmethod
from dataclasses import dataclass
class Device(ABC):
@abstractmethod
def set_channel(self, number: int) -> None:
pass
@abstractmethod
def turn_off(self) -> None:
pass
@abstractmethod
def turn_on(self) -> None:
pass
@dataclass
class RemoteControl:
device: Device
def turn_on(self) -> None:
self.device.turn_on()
def turn_off(self) -> None:
self.device.turn_off()
class AdvancedRemoteControl(RemoteControl):
def set_channel(self, number: int) -> None:
self.device.set_channel(number)
class SonyTV(Device):
def set_channel(self, number: int) -> None:
print('Sony set channel')
def turn_off(self) -> None:
print('Sony turn off')
def turn_on(self) -> None:
print('Sony turn on')
class SamsungTV(Device):
def set_channel(self, number: int) -> None:
print('Samsung set channel')
def turn_off(self) -> None:
print('Samsung turn off')
def turn_on(self) -> None:
print('Samsung turn on')
if __name__ == '__main__':
remote_control = RemoteControl(SonyTV())
remote_control.turn_on()
remote_control = AdvancedRemoteControl(SonyTV())
remote_control.turn_on()
remote_control = RemoteControl(SamsungTV())
remote_control.turn_on()