nono blog
楽しい人生を送りたい!
ITスキル

pythonプログラム デザインパターン(Builder)

デザインパターンとは、コーディングの最適なノウハウ

pythonに限らず、プログラミングをする場合は言語以上に様々なアルゴリズムやコーディングのノウハウがあります。

簡単なアプリケーションを作って、業務の効率化をするくらいであれば、サブルーチンのような関数と、メイン関数程度でも大体は事足りるかと思います。

しかし、もう少し踏み込んで保守性や拡張性の高いアプリケーションを作るには、オブジェクト指向の考え方を身につけることが欠かせません。

オブジェクト指向を初めて勉強した時に、これをどうやって扱えばいいのかわかりませんでした。単純に関数にした方がわかりやすいし、オブジェクトやインスタンスを作成するというのが、一体どういいのか理解ができませんでした。

そこで、過去のソフトウェア開発者が発見し編み出したソフトウェア開発の設計ノウハウがデザインパターンです。このデザインパターンを理解して、このルールに可能な限り則ってコーディングすることができれば、それだけでかなり品質の良いコーディングができるもの思います。

これから、多数のデザインパターンについて、pythonのサンプルコードと合わせて忘備録としてまとめていきます。

Builderパターン

Builder パターン

作成されるオブジェクトと作成するオブジェクトをそれぞれ分けたい場合に用いられる

(例)
Builderインターフェース(具体的な記述のない抽象クラス)

Builderインターフェースを継承した具体的なクラスを作成
・CarBuilder
・BusBuilder
・TruckBuilder

これらのクラスは、Builderインターフェースを前提としたコードでは
そのまま活用ができる

(目的)
同じ作成過程で異なる表現形式の結果を得ること。
>サブクラスに応じて、作成されるクラスのインスタンスの中身を変えることで実現する

構成要素
Product: 作成されるオブジェクト
Builder: Productを生成する処理を記述したインターフェース(抽象クラス)
CreateBuilder: Builderの処理を具体化したクラス(複数作成)
Director: Builderを利用するクラス

Builderパターンのサンプルコード

Builderパターンのサンプルコードを添付します。

# Builderパターン
from abc import ABC, abstractmethod, abstractproperty


# Product
class SetMeal(object):

    @property
    def main_dish(self):
        return self.__main_dish

    @main_dish.setter
    def main_dish(self, main_dish):
        self.__main_dish = main_dish

    @property
    def side_dish(self):
        return self.__side_dish

    @side_dish.setter
    def side_dish(self, side_dish):
        self.__side_dish = side_dish

    def __str__(self):
        return f'main dish:{self.main_dish}, side dish:{self.side_dish}'


# Builderのインターフェース
class SetMealBuilder(ABC):

    def __init__(self):
        self._set_meal = SetMeal()

    @abstractproperty
    def product(self):
        pass

    @abstractmethod
    def build_main_dish(self):
        pass

    @abstractmethod
    def build_side_dish(self):
        pass


# Builderインターフェースを継承した詳細クラスの作成
class SalmonSetBuilder(SetMealBuilder):

    def __init__(self):
        # 親クラスのコンストラクタを継承(実行)する
        super().__init__()

    @property
    def product(self):
        return self._set_meal

    def build_main_dish(self):
        self._set_meal.main_dish = 'Salmon'
        return self

    def build_side_dish(self):
        self._set_meal.side_dish = 'Miso Soup'
        return self


class PastaSetBuilder(SetMealBuilder):

    def __init__(self):
        super().__init__()

    @property
    def product(self):
        return self._set_meal

    def build_main_dish(self):
        self._set_meal.main_dish = 'Pasta'
        return self

    def build_side_dish(self):
        self._set_meal.side_dish = 'Soup'
        return self


# Director (外部から抽象クラスを呼び出すクラス)
# あくまで抽象クラスに依存する(依存性逆転の原則)
class Director(object):

    def __init__(self, set_meal_builder: SetMealBuilder):
        self.__builder = set_meal_builder

    @property
    def builder(self):
        return self.__builder

    @builder.setter
    def builder(self, builder: SetMealBuilder):
        self.__builder = builder

    def build(self):
        # self.builder.build_main_dish()
        # self.builder.build_side_dish()
        # 以下のように1行で書くこともできる
        self.builder.build_main_dish().build_side_dish()
        return self.builder


if __name__ == '__main__':
    """作成したBuilderパターンを使用してみよう"""
    salmon_builder = SalmonSetBuilder()
    pasta_builder = PastaSetBuilder()

    director = Director(salmon_builder)
    # director.builder() -> spel miss builder=>build
    print(director.build().product)

    director = Director(pasta_builder)
    print(director.build().product)