🐕

Builderパターンを学ぶ【Python】

2022/02/16に公開

一言で言うと

複雑な処理をDirectorクラスに隠蔽することによって交換可能性を高めることができる。

コードサンプル

ディレクトリ構造
builder
├── builder.py
├── director.py
├── html_builder.py
├── main.py
└── text_builder.py
main.py
import sys
from director import Director
from html_builder import HtmlBuilder
from text_builder import TextBuilder


def main(args: list[str]) -> None:
    if args[1] == 'plain':
        text_builder: TextBuilder = TextBuilder()
        director: Director = Director(text_builder)
        director.construct()
        print(text_builder.get_result())
    elif args[1] == 'html':
        html_builder: HtmlBuilder = HtmlBuilder()
        director: Director = Director(html_builder)
        director.construct()
        print(f'{html_builder.get_result()}が作成されました。')
    else:
        usage()
        exit(0)


def usage() -> None:
    print('Usage: python plain        プレーンテキストで文書を作成')
    print('Usage: python html         HTMLファイルで文書を作成')
    pass


if __name__ == '__main__':
    args = sys.argv
    # print(args)
    # > ['main.py', 'plain']
    if len(args) != 2:
        usage()
        exit(0)
    main(args)
director.py
from builder import Builder


class Director():
    def __init__(self, builder: Builder) -> None:
        self.builder: Builder = builder

    def construct(self) -> None:
        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.py
from abc import ABCMeta, abstractmethod


class Builder(metaclass=ABCMeta):
    @abstractmethod
    def make_title(self, title: str) -> None:
        pass

    @abstractmethod
    def make_string(self, str: str) -> None:
        pass

    @abstractmethod
    def make_items(self, items: list[str]) -> None:
        pass

    @abstractmethod
    def close(self) -> None:
        pass
director.py
from builder import Builder


class Director():
    def __init__(self, builder: Builder) -> None:
        self.builder: Builder = builder

    def construct(self) -> None:
        self.builder.make_title('Greeting')
        self.builder.make_string('朝から昼にかけて')
        self.builder.make_items(['おはようございます', 'こんにちは'])

        self.builder.make_string('夜に')
        self.builder.make_items(['こんばんは', 'おやすみなさい', 'さようなら'])
        self.builder.close()
html_builder.py
import io
from builder import Builder


class HtmlBuilder(Builder):
    def make_title(self, title: str):
        self.__file_name = f'{title}.html'
        self.__file: io.TextIOWrapper = io.open(self.__file_name, 'w',
                                                encoding='utf-8', newline='\n')
        self.__file.write(
            f'<html><head><title>{title}</title></head></body>\n')
        self.__file.write(f'<h1>{title}</h1>\n')

    def make_string(self, str: str) -> None:
        self.__file.write(f'<p>{str}</p>\n')

    def make_items(self, items: list[str]) -> None:
        self.__file.write('<ul>\n')
        for item in items:
            self.__file.write(f'<li>{item}</li>\n')
        self.__file.write('</ul>\n')

    def close(self) -> None:
        self.__file.write('</body></html>\n')
        self.__file.close()

    def get_result(self) -> str:
        return self.__file_name
text_builder.py
from builder import Builder


class TextBuilder(Builder):
    __str_buf: list = []

    def make_title(self, title: str):
        self.__str_buf.append('===============================')
        self.__str_buf.append(f'『{title}』')
        self.__str_buf.append('')

    def make_string(self, str: str) -> None:
        self.__str_buf.append(f'■{str}')
        self.__str_buf.append('')

    def make_items(self, items: list[str]) -> None:
        for item in items:
            self.__str_buf.append(f'  ・{item}')
        self.__str_buf.append('')

    def close(self) -> None:
        self.__str_buf.append('===============================')

    def get_result(self) -> str:
        return '\n'.join(self.__str_buf)

参考文献

実践python3
増補改訂版Java言語で学ぶデザインパターン入門

Discussion