Pythonで学ぶデザインパターン入門Builderパターン
結城先生の Java言語で学ぶデザインパターン入門
のコードを Python に書き直していくシリーズ第7段です。
Builderパターンとは
具体的な処理の骨組みを先につくっておくというパターンです。
Template Methodパターンでは、スーパークラスがサブクラスをコントロールしてましたが、このBuilderパターンでは他クラスでコントロールします。
ソースコード
コードの概要
文書を作成するプログラムを作成します。
文書を構成するためには、 Builder
クラスを継承します。 Builder
クラスを継承したクラスを、 Director
クラスがコントロールして文書を具体的に作るといったものになります。
ソースコード
Builder
# coding: utf-8 from abc import ABCMeta, abstractmethod class Builder(metaclass=ABCMeta): @abstractmethod def make_title(self, title: str): pass @abstractmethod def make_string(self, string: str): pass @abstractmethod def make_items(self, items: list): pass @abstractmethod def close(self): pass
文書を作成するための抽象クラスです。
後に紹介する Direcctor
クラスにコントロールされています。
Director
# coding: utf-8 from Builder.builder import Builder class Director(object): def __init__(self, builder: Builder): self.__builder = builder def construct(self): self.__builder.make_title('Greeting') self.__builder.make_string('朝から昼にかけて') self.__builder.make_items([ 'おはようございます。', 'こんにちは。' ]) self.__builder.make_string('夜に') self.__builder.make_items([ 'こんばんは。', 'おやすみなさい。', 'さようなら。' ]) self.__builder.close()
Builder
を継承したクラスをコントロールして文書を作成します。
construct
で文書を作成します。
TextBuilder(Builderを継承)
# coding: utf-8 from Builder.builder import Builder class TextBuilder(Builder): def __init__(self): self.__buffer = '' def make_title(self, title: str): self.__buffer += '================================\n' self.__buffer += '「%s」\n' % title self.__buffer += '\n' def make_string(self, string: str): self.__buffer += '■ %s \n' % string self.__buffer += '\n' def make_items(self, items: list): for i in items: self.__buffer += '・%s \n' % i self.__buffer += '\n' def close(self): self.__buffer += '================================\n' def get_result(self) -> str: return self.__buffer
テキストの文書を作成するクラスです。
最終的には文字列として文書が出力されます。
HTMLBuilder(Builderを継承)
# coding: utf-8 from Builder.builder import Builder class HTMLBuilder(Builder): def __init__(self): self.__filename = None def make_title(self, title: str): self.__filename = '%s.html' % title with open(self.__filename, 'a') as f: f.write('<html><head><title>%s</title></head><body>' % title) f.write('<h1>%s</h1>' % title) def make_string(self, string: str): with open(self.__filename, 'a') as f: f.write('<p>%s</p>' % string) def make_items(self, items: list): with open(self.__filename, 'a') as f: f.write('<ul>') for i in items: f.write('<li>%s</li>' % i) f.write('</ul>') def close(self): with open(self.__filename, 'a') as f: f.write('</body></html>') def get_result(self) -> str: return self.__filename
HTMLファイルとして文書が作成されるクラスです。
最終的にはファイル名が出力されます。
実行ファイル
# coding: utf-8 import sys from Builder.html_builder import HTMLBuilder from Builder.text_builder import TextBuilder from Builder.director import Director def usage(): print('python main.py plain プレーンテキストで文書作成') print('python main.py html HTMLファイルで文書作成') if __name__ == '__main__': if len(sys.argv) != 2: usage() exit() if sys.argv[1] == 'plain': html_builder = TextBuilder() director = Director(html_builder) director.construct() result = html_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) else: usage() exit()
実行結果
python Builder/main.py html Greeting.html python Builder/main.py plain ================================ 「Greeting」 ■ 朝から昼にかけて ・おはようございます。 ・こんにちは。 ■ 夜に ・こんばんは。 ・おやすみなさい。 ・さようなら。 ================================
実際どう便利か
Builderパターンを利用する時の便利な点は、Directorクラスは基本的に何も知らなくて良いことです。
Directorクラスは何も知らなくて良いのですが、ただどうやって文書を作成するかの方法だけを指定する必要があります。
実際、 Builderクラスを継承したインスタンスであればなんでもDirectorクラスは受け入れます。
Builderを継承したクラスを入れ替えることができるので、いろいろなBuilderクラスを構築して文書を作成することができます。