Credit: Concepts explained here are based on a book, “増補改訂版Java言語で学ぶデザインパターン入門”.
A bridge pattern builds a bridge between two kinds of classes: one working as abstraction and one working as implantation.
Let’s see a concrete example. Display and CountDisplay work as abstraction or User Interface. These classes delegate actual work to a class working as implementation. Display class functions so as to show some objects. An impl variable given to the constructor is an instance of a class working as an implementation. CountDisplay class is a subclass of Display class and shows some objects for specified times.
# display.py
class Display:
def __init__(self, impl):
self._impl = impl
def open(self):
self._impl.raw_open()
def print(self):
self._impl.raw_print()
def close(self):
self._impl.raw_close()
def display(self):
self.open()
self.print()
self.close()
# count_display.py
from display import Display
class CountDisplay(Display):
def __init__(self, impl):
super().__init__(impl)
def multi_display(self, times):
self.open()
for _ in range(times):
self.print()
self.close()
Now let’s create classes working as an implementation. DisplayImpl class is an abstract method and StringDisplayImpl class is a subclass of DisplayImpl and implements abstract methods defined in its parent class. This class encapsulates a given string with some characters and prints them out.
# display_impl.py
from abc import ABC, abstractmethod
class DisplayImpl(ABC):
@abstractmethod
def raw_open(self):
pass
@abstractmethod
def raw_print(self):
pass
@abstractmethod
def raw_close(self):
pass
# string_display_impl.py
from display_impl import DisplayImpl
class StringDisplayImpl(DisplayImpl):
def __init__(self, string):
self._string = string
self._width = len(string.encode("utf-8"))
def raw_open(self):
self.print_line()
def raw_print(self):
print(f"|{self._string}|")
def raw_close(self):
self.print_line()
def print_line(self):
print("+", end="")
for _ in range(self._width):
print("-", end="")
print("+")
Let’s run this program.
# main.py
from display import Display
from count_display import CountDisplay
from string_display_impl import StringDisplayImpl
def main():
d1 = Display(StringDisplayImpl("Hello, Japan."))
d2 = Display(StringDisplayImpl("Hello, World."))
d3 = CountDisplay(StringDisplayImpl("Hello, Universe."))
d1.display()
d2.display()
d3.display()
d3.multi_display(5)
if __name__ == "__main__":
main()
$ python main.py
+-------------+
|Hello, Japan.|
+-------------+
+-------------+
|Hello, World.|
+-------------+
+----------------+
|Hello, Universe.|
+----------------+
+----------------+
|Hello, Universe.|
|Hello, Universe.|
|Hello, Universe.|
|Hello, Universe.|
|Hello, Universe.|
+----------------+
One benefit of a Bridge pattern: Extending or modifying code in classes working as abstraction does not affect classes working as implementation and vice versa which means that there is no need to modify a class working as a different function. This is possible since each class is independent of each other.