Builder

ビルダーパターンの使用シーン

  • 複数のコンポーネントやオプションで構成されるオブジェクトを生成する場合

  • オブジェクトの生成プロセスが複数のステップに分かれており、それぞれのステップが複雑なロジックを含む場合

  • 同じ作成プロセスで異なる表現や構成を持つオブジェクトを生成したい場合

メリット

  1. 構築プロセスの詳細なカプセル化: オブジェクトの実際の構築方法をクライアントから隠すことができます。

  2. 製品のバリエーションを容易にする: 異なるビルダーを使用することで、異なる属性や特徴を持つオブジェクトを同じ構築プロセスで作成できます。

  3. オブジェクトの構築と表現の分離: ビルダーは最終オブジェクトの表現と構築プロセスを分離するため、同じ構築プロセスで異なる表現が得られます。

デメリット

  1. 設計が複雑になる: 小規模なオブジェクトの場合、ビルダーパターンを導入すると逆に設計が複雑になる可能性があります。

  2. コードの量が増加する: ビルダーとディレクターのクラスを追加する必要があるため、コード量が増えます。

サンプルコード(Python)

以下は、Pythonでのビルダーパターンのサンプル実装です。ここでは、異なるタイプの車両を構築する例を示しています。

from abc import ABC, abstractmethod

class VehicleBuilder(ABC):
    """車両ビルダーの抽象クラスです。すべてのビルダーはこのクラスを継承する必要があります。"""
    
    @abstractmethod
    def set_wheels(self, number_of_wheels):
        pass

    @abstractmethod
    def set_seats(self, number_of_seats):
        pass

    @abstractmethod
    def set_structure(self, structure_type):
        pass

    @abstractmethod
    def get_result(self):
        pass

class CarBuilder(VehicleBuilder):
    """車を構築する具体的なビルダークラスです。"""
    def __init__(self):
        self.vehicle = Vehicle()
    
    def set_wheels(self, number_of_wheels):
        self.vehicle.wheels = number_of_wheels
        return self
    
    def set_seats(self, number_of_seats):
        self.vehicle.seats = number_of_seats
        return self
    
    def set_structure(self, structure_type):
        self.vehicle.structure = structure_type
        return self
    
    def get_result(self):
        return self.vehicle

class Vehicle:
    """構築される車両のクラスです。"""
    def __init__(self):
        self.wheels = None
        self.seats = None
        self.structure = None
    
    def __str__(self):
        return f'Wheels: {self.wheels}, Seats: {self.seats}, Structure: {self.structure}'

class Director:
    """ビルダーオブジェクトを管理し、複数のビルダーを使用して異なるタイプの車両を構築します。"""
    def __init__(self):
        self._builder = None

    def construct(self, builder):
        self._builder = builder
        self._builder.set_wheels(4).set_seats(5).set_structure('Car')
        return self._builder.get_result()

# 使用例
director = Director()
car_builder = CarBuilder()
car = director.construct(car_builder)
print(car)

この例では、VehicleBuilder 抽象クラスを定義し、それを継承した CarBuilder クラスで具体的な車両の構築手順を定義しています。Director クラスは、構築プロセスを統括し、必要に応じて異なるビルダーを使い分けることができます。このようにビルダーパターンを使うことで、複雑なオブジェクトの構築を柔軟に制御できます。

ビルダーパターンの実用シナリオの例

1. ピザのオーダービルドシステム

ピザの注文システムはビルダーパターンを適用する典型的な例です。ピザは様々なトッピング、クラストタイプ、サイズなど、複数の選択肢でカスタマイズされます。ビルダーパターンを用いることで、異なるオプションを段階的に追加し、最終的な製品を組み立てるプロセスを簡単に管理できます。

2. コンピュータのカスタム組み立て

カスタムPCを組み立てる場合も、ビルダーパターンが有効です。ユーザーはプロセッサ、RAM、ストレージデバイス、グラフィックスカードなど、異なるハードウェアコンポーネントから選択して、自分のニーズに合わせたPCを構築します。ビルダーパターンによって、各ステップで正しい順序と構成が保証され、エラーの可能性を減少させます。

3. HTMLドキュメントジェネレーター

HTMLドキュメントを生成するシステムでは、異なるタグ(タイトル、ヘッダー、パラグラフなど)を組み合わせて全体のページを構築します。ビルダーパターンを使用することで、複雑な文書も段階的に確実に構築できます。

実用的なサンプルコード(Python)

ピザのオーダービルドシステム

以下は、ピザの注文をカスタマイズするシンプルなビルダーパターンの実装例です。

class PizzaBuilder:
    def __init__(self):
        self.pizza = Pizza()
    
    def set_dough(self, dough):
        self.pizza.dough = dough
        return self
    
    def set_sauce(self, sauce):
        self.pizza.sauce = sauce
        return self
    
    def set_topping(self, topping):
        self.pizza.topping = topping
        return self
    
    def build(self):
        return self.pizza

class Pizza:
    def __init__(self):
        self.dough = None
        self.sauce = None
        self.topping = None
    
    def __str__(self):
        return f'Dough: {self.dough}, Sauce: {self.sauce}, Topping: {self.topping}'

# クライアントコード
def main():
    builder = PizzaBuilder()
    pizza = (builder.set_dough("thick")
                    .set_sauce("tomato")
                    .set_topping("mozzarella cheese")
                    .build())
    print(pizza)

if __name__ == "__main__":
    main()

このコードでは、ピザのビルダークラスを使用して、異なるタイプの生地、ソース、トッピングを選択し、最終的なピザオブジェクトを構築しています。ビルダーパターンを使うことで、ピザの構築プロセスを柔軟に制御し、クライアントコードをシンプルに保つことができます。

HTMLドキュメントジェネレーター用ビルダーパターンのサンプルコード(Python)

以下の例では、HTMLドキュメントを段階的に構築するためのビルダーパターンを実装しています。これにより、複雑なHTML構造も簡単に管理し、拡張することができます。

class HTMLBuilder:
    """HTMLコンテンツを構築するためのビルダークラスです。"""
    
    def __init__(self):
        self.parts = []

    def add_title(self, title):
        """HTMLドキュメントにタイトルを追加します。
        
        Args:
            title (str): ドキュメントのタイトル。
        """
        self.parts.append(f"<title>{title}</title>")
        return self

    def add_heading(self, heading, level=1):
        """HTMLドキュメントに見出しを追加します。
        
        Args:
            heading (str): 見出しのテキスト。
            level (int): 見出しのレベル(h1, h2, ... h6)。デフォルトは1。
        """
        self.parts.append(f"<h{level}>{heading}</h{level}>")
        return self

    def add_paragraph(self, text):
        """HTMLドキュメントに段落を追加します。
        
        Args:
            text (str): 段落のテキスト。
        """
        self.parts.append(f"<p>{text}</p>")
        return self

    def build(self):
        """最終的なHTMLドキュメントを構築して返します。
        
        Returns:
            str: 完成したHTMLドキュメント。
        """
        return "<html>" + "".join(self.parts) + "</html>"

# クライアントコード
def main():
    builder = HTMLBuilder()
    html_content = (builder.add_title("My Document")
                           .add_heading("Welcome to My Document", level=1)
                           .add_paragraph("This is an example paragraph in our HTML document.")
                           .build())
    print(html_content)

if __name__ == "__main__":
    main()

メールの文を作成するためのビルダーパターンのサンプルコード(Python)

メールの文を作成する際にもビルダーパターンを適用することで、メールの構成要素(件名、宛先、本文など)を段階的に組み立てることができます。これにより、異なる種類のメールテンプレートを柔軟に扱うことが可能になります。

class EmailBuilder:
    """メールの文を構築するためのビルダークラスです。"""

    def __init__(self):
        self.email = {"subject": "", "recipient": "", "body": ""}

    def set_subject(self, subject):
        """メールの件名を設定します。
        
        Args:
            subject (str): メールの件名。
        """
        self.email["subject"] = subject
        return self

    def set_recipient(self, recipient):
        """メールの宛先を設定します。
        
        Args:
            recipient (str): メールの宛先。
        """
        self.email["recipient"] = recipient
        return self

    def add_paragraph(self, text):
        """メール本文に段落を追加します。
        
        Args:
            text (str): 追加するテキスト。
        """
        self.email["body"] += f"{text}\n\n"
        return self

    def build(self):
        """最終的なメールを構築して返します。
        
        Returns:
            dict: 構築されたメールの内容。
        """
        return self.email

# クライアントコード
def main():
    email_builder = EmailBuilder()
    email = (email_builder.set_subject("Meeting Reminder")
                        .set_recipient("johndoe@example.com")
                        .add_paragraph("Dear John,")
                        .add_paragraph("This is a reminder about your upcoming meeting tomorrow at 10am.")
                        .add_paragraph("Best regards,")
                        .add_paragraph("Jane Doe")
                        .build())
    print(email)

if __name__ == "__main__":
    main()

このメールビルダーは、メールの各部分を段階的に追加し、最終的なメールオブジェクトを生成します。このアプローチは特にカスタマイズが必要なメールの生成に適しており、異なる種類のメールを柔軟に作成することができます。

この記事が気に入ったらサポートをしてみませんか?