Verschiedene Möglichkeiten zur Implementierung des Python Builder-Musters

Zeeshan Afridi 21 Juni 2023
  1. Das Builder-Muster, seine Bedeutung und Funktionsweise
  2. Verschiedene Möglichkeiten zum Implementieren von Builder-Pattern in Python
  3. Vor- und Nachteile des Builder-Musters in Python
Verschiedene Möglichkeiten zur Implementierung des Python Builder-Musters

Das Builder-Muster ist ein Muster, das es ermöglicht, die Erstellung eines Objekts von seiner Darstellung zu trennen. Dieses Muster kann komplexe Objekte ohne Vererbung erstellen und konfigurieren, was ein leistungsfähiger, aber unflexibler Ansatz ist.

Das Builder-Muster kann auch verwendet werden, um verschiedene Implementierungen einer Klasse zur Laufzeit bereitzustellen oder Benutzern zu ermöglichen, neue Objekte zu erstellen, ohne Zugriff auf den Quellcode zu haben.

In diesem Tutorial erfahren Sie mehr über Builder-Muster und wie sie funktionieren. Es zeigt auch verschiedene Möglichkeiten zur Implementierung von Python-Builder-Mustern.

Das Builder-Muster, seine Bedeutung und Funktionsweise

Das Builder-Muster ist das Software-Entwurfsmuster, mit dem die Konstruktion komplexer Objekte Schritt für Schritt erstellt werden kann, wodurch eine neue Detailebene oder Funktionalität bereitgestellt wird.

Dieses Muster wird häufig in der Softwareentwicklung verwendet, wo verschiedene Softwarekomponenten zu einem Gesamtsystem kombiniert werden müssen.

Das Builder-Muster kann verwendet werden, um alles zu erstellen, von einfachen Objekten wie einem Tisch oder einem Stuhl bis hin zu komplexeren Systemen wie einem Computer oder einem Flugzeug. Es ist auch hilfreich, um Objekte zu erstellen, die in einer bestimmten Reihenfolge erstellt werden müssen.

Die Python-Standardbibliothek stellt ein Modul namens builder bereit, das die Verwendung des Builder-Musters vereinfacht. Das Builder-Modul bietet zwei Klassen, den Builder und den Director, die zusammenarbeiten, um Objekte zu erstellen.

Die Klasse Builder ist für die Erstellung der Objektteile verantwortlich, und die Klasse Director wird verwendet, um die Komponenten zum endgültigen Objekt zusammenzusetzen.

Um das Builder-Muster zu verwenden, erstellen Sie zuerst ein Builder-Objekt, mit dem Sie die Teile des Objekts erstellen. Dann erstellen Sie ein Director-Objekt, mit dem Sie die Teile zum endgültigen Objekt zusammensetzen.

Schließlich können Sie die Methode build() für das Objekt Director aufrufen, die das endgültige Objekt zurückgibt.

Verschiedene Möglichkeiten zum Implementieren von Builder-Pattern in Python

Es gibt zwei Methoden, um das Builder-Pattern in Python zu implementieren:

  1. Die __init__-Methode
  2. Die __new__-Methode

Verwenden Sie die __init__-Methode

Die Methode __init__ ist die gebräuchlichste Art, das Muster Builder in Python zu implementieren. Es wird aufgerufen, wenn das Objekt erstellt wird, und ermöglicht es Ihnen, die Werte seiner Attribute festzulegen.

Verwenden Sie die __new__-Methode

Die Methode __new__ ist weniger gebräuchlich, aber leistungsfähiger. Beim Erstellen der Klasse wird die Methode __new__ aufgerufen, mit der Sie das Objekt selbst erstellen können.

Das bedeutet, dass Sie steuern können, wie das Objekt erstellt wird, und sogar Objekte erstellen können, die nicht denselben Typ wie die Klasse haben.

Vor- und Nachteile des Builder-Musters in Python

Es gibt einige Vorteile von Builder-Mustern, die unten aufgeführt sind:

  • Der wesentliche Vorteil des Builder-Musters besteht darin, dass es die schrittweise Erstellung komplexer Objekte ermöglicht und eine neue Detailebene oder Funktionalität bietet.
  • Dadurch wird das Erstellen komplexer Objekte viel einfacher und effizienter.
  • Das Builder-Muster ist auch vorteilhaft, da es ein hohes Maß an Flexibilität ermöglicht, da verschiedene Builder unterschiedliche Arten von Objekten erstellen können.

Es gibt auch einige Nachteile bei der Verwendung des Builder-Musters.

  • Einer ist, dass das Erstellen eines Objekts ziemlich zeitaufwändig sein kann, da jeder Schritt der Reihe nach ausgeführt werden muss.
  • Ein weiterer Nachteil ist, dass das Builder-Muster ziemlich komplex sein kann und viel Code zum Schreiben erfordert.

Codebeispiel:

from __future__ import annotations
from abc import ABC, abstractmethod
from typing import Any


class Builder(ABC):
    @property
    @abstractmethod
    def product(self) -> None:
        pass

    @abstractmethod
    def produce_a(self) -> None:
        pass

    """
    This class will provide specific working of the building steps by using the builder interface.
    """


class ConcreteBuilder1(Builder):
    def __init__(self) -> None:
        """This fresh builder instance will contain a blank product object, which is
        used in further assembly.
        """
        self.reset()

    def reset(self) -> None:
        self._product = Product1()

    @property
    def product(self) -> Product1:

        product = self._product
        self.reset()
        return product

    def produce_a(self) -> None:
        self._product.add("PartA")


class Product1:
    """
    When your products are complex and demand extensive configuration, it's possible to use the Builder pattern only.
    """

    def __init__(self) -> None:
        self.parts = []

    def add(self, part: Any) -> None:
        self.parts.append(part)

    def list_parts(self) -> None:
        print(f"The Product parts: {', '.join(self.parts)}", end="")


class Director:
    """
    The client can control builders directly, so the Director class is
     optional. In this case, the Director is only responsible for executing the building steps in a specific sequence.
    """

    def __init__(self) -> None:
        self._builder = None

    @property
    def builder(self) -> Builder:
        return self._builder
        """
    The Director can construct several product variations using the same
    building steps.
    """

    @builder.setter
    def builder(self, builder: Builder) -> None:
        self._builder = builder

    def build_minimal_viable_product(self) -> None:
        self.builder.produce_a()

    def build_full_featured_product(self) -> None:
        self.builder.produce_a()


if __name__ == "__main__":

    director = Director()
    builder = ConcreteBuilder1()
    director.builder = builder

    print("Our Standard primary product:")
    director.build_minimal_viable_product()
    builder.product.list_parts()

    print("\n")

    print("Our Standard full-featured product:")
    director.build_full_featured_product()
    builder.product.list_parts()

    print("\n")
    # We can also use the Builder pattern without a Director class.
    print("Our Custom product: ")
    builder.produce_a()
    builder.product.list_parts()

Ausgang:

Our Standard primary product:
The Product parts: PartA

Our Standard full-featured product:
The Product parts: PartA

Our Custom product: 
The Product parts: PartA

Denken Sie daran, dass das Builder-Muster auch ein Entwurfsmuster ist, das dabei hilft, komplexe Objekte zu erstellen, indem Konstruktion und Darstellung getrennt werden. Diese Trennung ermöglicht es, unterschiedliche Darstellungen aus dem gleichen Konstruktionsprozess zu machen.

Zeeshan Afridi avatar Zeeshan Afridi avatar

Zeeshan is a detail oriented software engineer that helps companies and individuals make their lives and easier with software solutions.

LinkedIn