I practiced design patterns so that I could write code that was conscious of design. Other Design Patterns will be released frequently.
The primary goal is to understand when, what, and how to use design patterns. (I'm new to Java or a statically typed language, and I don't have a long history of python, so I think there are some things that aren't like Pythonista. If you have any suggestions, please teach me.)
This time, the creational pattern Builder.
When the object creation procedure is complicated, the creation process is encapsulated and an instance with a structure is assembled. In addition, by preparing various pattern builders, it is possible to handle the production of various patterns, and even complicated method combinations can be executed collectively.
As a sample, create a program that creates "sentences" using the Builder pattern. The text created here has the following structure.
The Builder class defines the methods for constructing the document. The Director class then uses that method to create a concrete document,
The Builder class is an abstract class and the actual processing is not written. Only the abstract method is declared. It is the subclass of the Builder class that determines the specific processing for writing.
Director can use TextBuilder to create plain text documents, and HTMLBuilder can be used to create HTML documents.
builder.py
from abc import ABCMeta, abstractmethod
class Builder(metaclass=ABCMeta):
@abstractmethod
def make_title(self, title):
pass
@abstractmethod
def make_string(self, string):
pass
@abstractmethod
def make_items(self, items):
pass
@abstractmethod
def close(self):
pass
The Builder class is an abstract class that declares the methods that create "documents". make_title, make_string, and make_items are methods for constructing titles, strings, and bullets in sentences, respectively. The close method is the method that completes the document.
director.py
class Director():
def __init__(self, builder):
self.__builder = builder
def construct(self):
self.__builder.make_title('Greeting')
self.__builder.make_string('From morning to noon')
string = ['Good morning.', 'Hello.']
self.__builder.make_items(string)
self.__builder.make_string('At night')
string = ['Good evening.', 'good night.', 'goodbye.']
self.__builder.make_items(string)
self.__builder.close()
In the Director class, the document is created using the methods declared in the Builder class.
The argument of the constructor of the Director class is a subclass (TextBuilder class or HTMLBuilder) type of the Builder class. The Builder class is an abstract class, so you can't instantiate it. The type of subclass of the given Builder class determines the specific document format created by the Director class.
The construct method is a method to create a document. Calling this method builds the document. The construct method uses the methods declared in the Builder.
text_builder.py
from builder import Builder
class TextBuilder(Builder):
__buffer = []
def make_title(self, title):
self.__buffer.append('=' * 20)
self.__buffer.append('[' + title + ']\n')
self.__buffer.append('\n')
def make_string(self, string):
self.__buffer.append('■' + string + '\n')
self.__buffer.append('\n')
def make_items(self, items):
for i in range(0, len(items)):
self.__buffer.append('●' + items[i] + '\n')
self.__buffer.append('\n')
def close(self):
self.__buffer.append('=' * 20)
def get_result(self):
for buffer in self.__buffer:
print(buffer)
The TextBuilder class is a subclass of the Builder class. Build your document using plain text. The result is returned as a String.
html_builder.py
import logging
from builder import Builder
class HTMLBuilder(Builder):
def make_title(self, title):
self.__filename = title + '.html'
try:
self.__writer = open(self.__filename, mode='w')
except IOError as e:
logging.exception(e)
self.__writer.write('<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>' + title + '</title></head><body>')
self.__writer.write('<h1>' + title + '<h1>')
def make_string(self, string):
self.__writer.write('<h1>' + string + '</p>')
def make_items(self, items):
self.__writer.write('<ul>')
for i in range(0, len(items)):
self.__writer.write('<li>' + items[i] + '</li>')
self.__writer.write('</ul>')
def close(self):
self.__writer.write('</body></html>')
self.__writer.close()
def get_result(self):
return self.__filename
The HTMLBuilder class is also a subclass of the Builder class. The HTMLBuilder class builds a document as an HTML file. The constructed result is returned as the file name of the HTML file.
main.py
import sys
from text_builder import TextBuilder
from html_builder import HTMLBuilder
from director import Director
def usage():
print('Usage: Python main plain')
print('Usage: Python main html')
def main():
if len(sys.argv) != 2:
usage()
sys.exit()
if sys.argv[1] == 'plain':
text_builder = TextBuilder()
director = Director(text_builder)
director.construct()
result = text_builder.get_result()
print(result)
elif sys.argv[1] == 'html':
html_builder = HTMLBuilder()
director = Director(html_builder)
director.construct()
filename = html_builder.get_result()
print(filename + 'Has been created.')
else:
usage()
sys.exit()
if __name__ == "__main__":
main()
The main file is a test program for the Builder pattern. Create a document according to the format specified on the command line as shown below.
python main.py plain ・ ・ ・ Create a document in plain text python main.py html ・ ・ ・ Document creation with HTML file
If you specify ** plain ** on the command line, you pass an instance of the TextBuilder class to the constructor of the Director class. Also, if you specify ** html ** on the command line, pass an instance of the HTMLBuilder class to the constructor of the Director class.
Both TextBuilder and HTMLBuilder are subclasses of Builder, and Director uses only Builder methods to create documents. Using only Builder methods means that ** Director is unaware of whether TextBuilder or HTMLBuilder is actually running **.
Therefore, the Builder must declare a set of methods necessary and sufficient to achieve the purpose of building the document. However, the Builder must not provide methods that are specific to plain text or HTML files.
Execution result (plain)
====================
[Greeting]
■ From morning to noon
● Good morning.
● Hello.
■ At night
● Good evening.
● Good night.
● Goodbye.
====================
Execution result (html)
`Greeting.html has been created. ``
A builder pattern specialized for reducing the instance creation work when the instance creation procedure and contents are complicated.
Regarding the procedure, the difference between the Template Method pattern and the Builder pattern is who is responsible for instantiation. The Template Method pattern determines the procedure for instantiation in a superclass. On the other hand, for the Builder pattern, the Director class (other class) is responsible for the generation procedure.
The key to the Builder pattern is who knows how to create an instance, that is, the Director class. It's also important that users of Director must know what the instance created by the Builder is.
It seems that the Builder pattern comes into play when there is a procedure for creating an instance, when you have to create an instance using an external resource, or when there are many different arguments in the constructor.
Recommended Posts