Credit: Concepts explained here are based on a book, “増補改訂版Java言語で学ぶデザインパターン入門”.
A builder pattern is a pattern in which an instance is created by calling a class which in turn calls an interface which is a framework for objects to be built.
Let’s create a sample program in which a document is created. A document is created by calling a Director class which calls a Builder interface. TextBuilder and HTMLBuilder classes implement a Builder interface.
A Builder class has three abstract methods which make title, strings and items of lists.
# builder.py
from abc import ABC, abstractmethod
class Builder(ABC):
@abstractmethod
def make_title(self, title):
pass
@abstractmethod
def make_string(self, sting):
pass
@abstractmethod
def make_items(self, items):
pass
@abstractmethod
def close(self):
pass
A Director class has a builder instance as an attribute by which title, string and items are created. A builder instance given to the constructor is an instance of a subclass of a Builder class that implements concrete algorithm for each abstract method.
# director.py
class Director:
def __init__(self, builder):
self._builder = builder
def construct(self):
self._builder.make_title("Greeting")
self._builder.make_string("Moring to Afternoon")
self._builder.make_items(["Good Morning", "Good afternoon"])
self._builder.make_string("At nignt")
self._builder.make_items(["Good evening", "Good night", "Goodbye"])
self._builder.close()
A TextBuilder class is a subclass of a Builder class. This class creates a text from given strings.
# text_builder.py
from builder import Builder
from string_buffer import StringBuffer
class TextBuilder(Builder):
def __init__(self):
self._buffer = StringBuffer()
def make_title(self, title):
self._buffer.append("==============================\n")
self._buffer.append(f"[ {title} ]\n")
self._buffer.append("\n")
def make_string(self, string):
self._buffer.append(f"■ {string} \n")
self._buffer.append(f"\n")
def make_items(self, items):
for i in range(len(items)):
self._buffer.append(f" ・{items[i]}\n" )
self._buffer.append("\n")
def close(self):
self._buffer.append("==============================\n")
def get_result(self):
return self._buffer.to_string()
A HTMLBuilder is a subclass of a Builder class. This class creates a HTML file from given strings.
# html_builder.py
from builder import Builder
class HTMLBuilder(Builder):
def __init__(self):
self._filename = None
self._writer = None
def make_title(self, title):
self._filename = title + ".html"
self._writer = open(self._filename, "w")
self._writer.write(f"<html><head><title>{title}</title></head><body>\n")
self._writer.write(f"<h1>{title}</h1>\n")
def make_string(self, string):
self._writer.write(f"<p>{string}</p>\n")
def make_items(self, items):
self._writer.write("<ul>")
for i in range(len(items)):
self._writer.write(f"<li>{items[i]}</li>\n")
self._writer.write("</ul>\n")
def close(self):
self._writer.write("</body></html>\n")
self._writer.close()
def get_result(self):
return self._filename
A StringBuffer is a helper class which holds a list of strings and converts it to a text.
# string_buffer.py
class StringBuffer:
def __init__(self):
self._strings = []
def append(self, string):
self._strings.append(string)
def to_string(self):
return " ".join(self._strings)
Let’s run this program.
# main.py
from director import Director
from text_builder import TextBuilder
from html_builder import HTMLBuilder
def main(text_kind):
if text_kind == "plain":
print("Create a plain text.")
text_builder = TextBuilder()
director = Director(text_builder)
director.construct()
result = text_builder.get_result()
print(result)
elif text_kind == "html":
print("Create a html file.")
html_builder = HTMLBuilder()
director = Director(html_builder)
director.construct()
filename = html_builder.get_result()
print(f"{filename} is created.")
else:
print("No argument is passed.")
if __name__ == "__main__":
main("plain")
main("html")
# Result
Create a plain text.
==============================
[ Greeting ]
■ Moring to Afternoon
・Good Morning
・Good afternoon
■ At nignt
・Good evening
・Good night
・Goodbye
==============================
Create a html file.
Greeting.html is created.
<!-- Greeting.html -->
<html><head><title>Greeting</title></head><body>
<h1>Greeting</h1>
<p>Moring to Afternoon</p>
<ul><li>Good Morning</li>
<li>Good afternoon</li>
</ul>
<p>At nignt</p>
<ul><li>Good evening</li>
<li>Good night</li>
<li>Goodbye</li>
</ul>
</body></html>
One benefit of a Builder pattern: It makes it possible to create an object, a document in the sample program without modifying a Director or a Builder class. In this example, since a Director class does not know the instance of a subclass of a Builder class is, it is possible to modify a subclass without affecting other classes.