Learn the design pattern "Bridge" in Python

As a material for learning GoF design patterns, the book "Introduction to Design Patterns Learned in the Augmented and Revised Java Language" seems to be helpful. However, since the examples taken up are based on JAVA, I tried the same practice in Python to deepen my understanding.

■ Bridge (bridge pattern)

The Bridge pattern is one of the design patterns defined by GoF (Gang of Four; 4 gangs). The purpose is to extend the class in multiple directions by preparing a "bridging" class.

UML class and sequence diagram W3sDesign_Bridge_Design_Pattern_UML.jpg UML class diagram bridge.png (The above is quoted from Wikipedia)

□ Memorandum

The Bridge pattern seems to bridge the ** feature class hierarchy ** and the ** implementation class hierarchy **.

(1) What is the function class hierarchy?

If you want to add new functionality to a class, define a new subclass and implement the method. The relationship between an existing superclass and a newly defined subclass is the "functional class hierarchy". In general, assume the following relationships.

--Superclass has basic functions --Add new features in subclasses

(2) What is the implementation class hierarchy?

If you want to add a new implementation, define a concrete subclass derived from the abstract class and then implement the method. The relationship between an existing abstract class and a newly derived concrete subclass is the "implementation class hierarchy". In general, assume the following relationships.

--In the abstract class, the interface is defined by the abstract method. --Derived subclasses implement their interface with concrete methods

■ "Bridge" sample program

I would like to actually run a sample program that utilizes the Bridge pattern and check the following behavior. This is a sample that assumes a bridge between the ** function class hierarchy ** and the ** implementation class hierarchy **.

--Display a string through the bridge between DisplayFunc and DisplayStringImpl --Display a string through the bridge between DisplayCountFunc and DisplayStringImpl --Display a string through the bridge between DisplayCountFunc and DisplayStringImpl --The character string is displayed repeatedly 5 times through the bridge between DisplayRandomFunc and DisplayStringImpl. --The character string is displayed repeatedly at random times through the bridge between DisplayRandomFunc and DisplayStringImpl. --Display the contents of the text file via the bridge between DisplayFunc and DisplayTextfileImpl

$ python Main.py 
+-----------+
|Hello Japan|
+-----------+

+-----------+
|Hello Japan|
+-----------+

+--------------+
|Hello Universe|
+--------------+

+--------------+
|Hello Universe|
|Hello Universe|
|Hello Universe|
|Hello Universe|
|Hello Universe|
+--------------+

+--------------+
|Hello Universe|
|Hello Universe|
|Hello Universe|
|Hello Universe|
+--------------+

aaa
bbb
ccc
ddd
eee
fff
ggg

If you just run the sample program, you don't really know what you want to do. Next, let's check the details of the sample program.

■ Details of sample program

Similar code has been uploaded to the Git repository. https://github.com/ttsubo/study_of_design_pattern/tree/master/Bridge

--Directory structure

.
├── Main.py
├── bridge
│   ├── __init__.py
│   ├── function
│   │   ├── __init__.py
│   │   ├── display_count_func.py
│   │   ├── display_func.py
│   │   └── display_random_func.py
│   └── implement
│       ├── __init__.py
│       ├── display_impl.py
│       ├── display_string_impl.py
│       └── display_textfile_impl.py
└── test.txt

(1) The role of Abstraction

It is a class that implements only basic functions using the method of ʻImplement. In the sample program, the DisplayFunc` class serves this role.

bridge/function/display_func.py


class DisplayFunc(object):
    def __init__(self, impl):
        self.impl = impl

    def open(self):
        self.impl.rawOpen()

    def print_body(self):
        self.impl.rawPrint()

    def close(self):
        self.impl.rawClose()

    def display(self):
        self.open()
        self.print_body()
        self.close()

(2) The role of Refined Abstraction

ʻAbstractionThis is a role with additional functions. In the sample program, theDisplayCountFunc class and the DisplayRandomFunc` class serve this role.

bridge/function/display_count_func.py


from bridge.function.display_func import DisplayFunc

class DisplayCountFunc(DisplayFunc):
    def __init__(self, impl):
        super(DisplayCountFunc, self).__init__(impl)

    def multiDisplay(self, times):
        self.open()
        for _ in range(times):
            self.print_body()
        self.close()

bridge/function/display_random_func.py


import random
from bridge.function.display_func import DisplayFunc

class DisplayRandomFunc(DisplayFunc):
    def __init__(self, impl):
        super(DisplayRandomFunc, self).__init__(impl)

    def randomDisplay(self, times):
        self.open()
        t = random.randint(0, times)
        for _ in range(t):
            self.print_body()
        self.close()

(3) The role of Implementor

ʻAbstractionThis is the role that defines the method for implementing the interface. In the sample program, theDisplayImpl` class serves this role.

bridge/implement/display_impl.py


from abc import ABCMeta, abstractmethod

class DisplayImpl(metaclass=ABCMeta):
    @abstractmethod
    def rawOpen(self):
        pass

    @abstractmethod
    def rawPrint(self):
        pass

    @abstractmethod
    def rawClose(self):
        pass

(4) The role of Concrete Implementor

Specifically, it is the role of implementing the interface of the role of ʻImplement. In the sample program, the DisplayStringImpl class and the DisplayTextfileImpl` class serve this role.

bridge/implement/display_string_impl.py


from bridge.implement.display_impl import DisplayImpl

class DisplayStringImpl(DisplayImpl):
    def __init__(self, string):
        self.string = string
        self.width = len(string)

    def rawOpen(self):
        self.printLine()

    def rawPrint(self):
        print("|{0}|".format(self.string))

    def rawClose(self):
        self.printLine()
        print("")

    def printLine(self):
        line = '-' * self.width
        print("+{0}+".format(line))

bridge/implement/display_textfile_impl.py


from bridge.implement.display_impl import DisplayImpl

class DisplayTextfileImpl(DisplayImpl):
    def __init__(self, filename):
        self.filename = filename

    def rawOpen(self):
        filename = self.filename
        self.f = open(filename, "r")

    def rawPrint(self):
        data = self.f.read()
        data = data.split('\n')
        for l in data:
            print(l)

    def rawClose(self):
        self.f.close()

(5) The role of Client

In the sample program, the startMain method serves this role.

Main.py


from bridge.function.display_func import DisplayFunc
from bridge.function.display_count_func import DisplayCountFunc
from bridge.function.display_random_func import DisplayRandomFunc
from bridge.implement.display_string_impl import DisplayStringImpl
from bridge.implement.display_textfile_impl import DisplayTextfileImpl

def startMain():
    d1 = DisplayFunc(DisplayStringImpl("Hello Japan"))
    d2 = DisplayCountFunc(DisplayStringImpl("Hello Japan"))
    d3 = DisplayCountFunc(DisplayStringImpl("Hello Universe"))
    d4 = DisplayRandomFunc(DisplayStringImpl("Hello Universe"))
    d5 = DisplayFunc(DisplayTextfileImpl("test.txt"))
    d1.display()
    d2.display()
    d3.display()
    d3.multiDisplay(5)
    d4.randomDisplay(5)
    d5.display()

if __name__ == '__main__':
    startMain()

■ Reference URL

-[Finishing "Introduction to Design Patterns Learned in Java Language" (Not)](https://medium.com/since-i-want-to-start-blog-that-looks-like-men-do/java Introduction to Design Patterns Learned in Language-Finishing-Not-2cc9b34a30b2) -Bridge pattern from "diary of tachikawa844"

Recommended Posts

Learn the design pattern "Bridge" in Python
Learn the design pattern "Prototype" in Python
Learn the design pattern "Flyweight" in Python
Learn the design pattern "Memento" in Python
Learn the design pattern "Proxy" in Python
Learn the design pattern "Command" in Python
Learn the design pattern "Visitor" in Python
Learn the design pattern "Mediator" in Python
Learn the design pattern "Decorator" in Python
Learn the design pattern "Iterator" in Python
Learn the design pattern "Strategy" in Python
Learn the design pattern "Composite" in Python
Learn the design pattern "State" in Python
Learn the design pattern "Adapter" in Python
Learn the design pattern "Abstract Factory" in Python
Learn the design pattern "Template Method" in Python
Learn the design pattern "Factory Method" in Python
Learn the design pattern "Chain of Responsibility" in Python
Learn the design pattern "Singleton" with Python
Learn the design pattern "Facade" with Python
Implement the Singleton pattern in Python
Singleton pattern in Python
Visitor pattern in Python
Download the file in Python
Find the difference in Python
Learn cumulative sum in Python
Design Patterns in Python: Introduction
Learn exploration in Python # 1 Full exploration
Python Design Pattern --Template method
Getting the arXiv API in Python
Python in the browser: Brython's recommendation
Hit the Sesami API in Python
Get the desktop path in Python
Get the script path in Python
In the python command python points to python3.8
Hit the web API in Python
I wrote the queue in Python
Calculate the previous month in Python
Examine the object's class in python
Get the desktop path in Python
Get the host name in Python
Access the Twitter API in Python
The first step in Python Matplotlib
I wrote the stack in Python
Master the weakref module in Python
Learn the basics of Python ① Beginners
Load the remote Python SDK in IntelliJ
Try using the Wunderlist API in Python
[Python Kivy] About changing the design theme
Try using the Kraken API in Python
Learn the basics while touching python Variables
Write the test in a python docstring
OR the List in Python (zip function)
Display Python 3 in the browser with MAMP
Tweet using the Twitter API in Python
Check if the URL exists in Python
Associate the table set in python models.py
Run the Python interpreter in a script
The result of installing python in Anaconda
What is "mahjong" in the Python library? ??
Read the file line by line in Python