[GO] Learn the design pattern "Builder" 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.

■ Builder

The Builder pattern (builder pattern) is one of the design patterns defined by GoF (Gang of Four; 4 gangs). By abstracting the object creation process, it enables dynamic object creation. UML class and sequence diagram W3sDesign_Builder_Design_Pattern_UML.jpg UML class diagram 2880px-Builder_UML_class_diagram.svg-2.png (The above is quoted from Wikipedia)

■ "Builder" sample program

Since it is difficult to assemble a builder pattern with a complicated structure at once, it seems that each part that composes the whole is created in advance and an instance with a structure is assembled step by step. Actually, I would like to use the Builder pattern to run a sample program that creates a "document" and see how it works.

--When operated in plain mode, a document in plain text format is output. --When operated in html mode, an HTML file of tabular links is generated.

(1) Try running in plain mode

First, let's move the code output by the plain text format document.

$ python Main.py plain
======================
Greeting

*** From the morning to the afternoon ***
- Good morning
- Hello
*** In the evening ***
- Good evening
- Good night
- Good bye
======================

A so-called plain text document was output.

(2) Try moving the html mode

Next, let's run the code that creates a ** Table-based ** web page.

$ python Main.py html
[Greeting.html] was created.

A file called Greeting.html has been generated. When I checked the appearance with a web browser, it looked like this. tablehtml.png

■ Details of sample program

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

--Directory structure

.
├── Main.py
└── builder
    ├── __init__.py
    ├── builder.py
    ├── director.py
    ├── htmlbuilder
    │   ├── __init__.py
    │   └── html_builder.py
    └── textbuilder
        ├── __init__.py
        └── text_builder.py

(1) The role of Builder

The Builder role defines the interface for creating an instance. The Builder role provides methods for creating each part of the instance. In the sample program, the Builder class serves this role.

builder/builder.py


from abc import ABCMeta, abstractmethod

class Builder(metaclass=ABCMeta):
    @abstractmethod
    def makeTitle(self, title):
        pass

    @abstractmethod
    def makeString(self, str):
        pass

    @abstractmethod
    def makeItems(self, items):
        pass

    @abstractmethod
    def close(self):
        pass

(2) The role of Concrete Builder

The ConcreteBuilder role is a class that implements the interface for the Builder role. The methods that are called during the actual instantiation are defined here. It also provides a method to get the final result. In the sample program, the TextBuilder class and the HTMLBuilder class serve this role.

builder/text_builder.py


from builder.builder import Builder

class TextBuilder(Builder):
    def __init__(self):
        self.buffer = []

    def makeTitle(self, title):
        self.buffer.append("======================\n")
        self.buffer.append(title + "\n")
        self.buffer.append("\n")

    def makeString(self, str):
        self.buffer.append("*** " + str + " ***" + "\n")

    def makeItems(self, items):
        for i in items:
            self.buffer.append("- " + i + "\n")

    def close(self):
        self.buffer.append("======================\n")

    def getResult(self):
        return ''.join(self.buffer)

builder/html_builder.py


from builder.builder import Builder

class HTMLBuilder(Builder):
    def __init__(self):
        self.buffer = []
        self.filename = ""
        self.f = None
        self.makeTitleCalled = False

    def makeTitle(self, title):
        self.filename = title+".html"
        self.f = open(self.filename, "w")
        self.f.write("<html><head><title>"+title+"</title></head></html>")
        self.f.write("<h1>"+title+"</h1>")
        self.makeTitleCalled = True

    def makeString(self, str):
        if not self.makeTitleCalled:
            raise RuntimeError
        self.f.write("<p>"+str+"</p>")

    def makeItems(self, items):
        if not self.makeTitleCalled:
            raise RuntimeError
        self.f.write("<ul>")
        for i in items:
            self.f.write("<li>"+i+"</li>")
        self.f.write("</ul>")

    def close(self):
        if not self.makeTitleCalled:
            raise RuntimeError
        self.f.write("</body></html>")
        self.f.close()

    def getResult(self):
        return self.filename

(3) The role of Director

The Director role creates an instance using the interface of the Builder role. No programming that depends on the ConcreteBuilder role is performed. Only use the methods of the ** Builder role ** so that it works well no matter what the ConcreteBuilder role is. In the sample program, the Director class serves this role.

builder/director.py


class Director(object):
    def __init__(self, builder):
        self.__builder = builder

    def construct(self):
        self.__builder.makeTitle("Greeting")
        self.__builder.makeString("From the morning to the afternoon")
        self.__builder.makeItems(["Good morning", "Hello"])
        self.__builder.makeString("In the evening")
        self.__builder.makeItems(["Good evening", "Good night", "Good bye"])
        self.__builder.close()

(4) The role of Client

It is a role that uses the Builder role. In the sample program, the startMain method serves this role.

Main.py


import sys

from builder.director import Director
from builder.textbuilder.text_builder import TextBuilder
from builder.htmlbuilder.html_builder import HTMLBuilder

def startMain(opt):
    if opt == "plain":
        builder = TextBuilder()
        director = Director(builder)
        director.construct()
        result = builder.getResult()
        print(result)
    elif opt == "html":
        builder = HTMLBuilder()
        director = Director(builder)
        director.construct()
        result = builder.getResult()
        print("[" + result + "]" + " was created.")


if __name__ == "__main__":
    startMain(sys.argv[1])

■ 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) -Builder pattern from "diary of tachikawa844"

Recommended Posts

Learn the design pattern "Builder" in Python
Learn the design pattern "Prototype" in Python
Learn the design pattern "Flyweight" in Python
Learn the design pattern "Observer" 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 "Bridge" 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
Design Pattern #Builder
Singleton pattern in Python
Visitor pattern in Python
Download the file in Python
Find the difference in Python
I wrote a design pattern in kotlin Builder edition
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
Save the binary file in Python
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
Check the behavior of destructor 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)
GoF design pattern from the problem 2. Structure
Display Python 3 in the browser with MAMP