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.
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 UML class diagram (The above is quoted from Wikipedia)
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.
plain
modeFirst, 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.
html
modeNext, 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.
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
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
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
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()
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])
-[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