Patrón creacional Builder(Python) - fapaccha/Dise-o-dirigido-por-el-modelo GitHub Wiki

Builder(Python)

Const

Builder es un patrón de diseño creacional que nos permite construir objetos complejos paso a paso. El patrón nos permite producir distintos tipos y representaciones de un objeto empleando el mismo código de construcción.

Estructura

EstructuraBuilderPython

  1. La interfaz Constructora declara pasos de construcción de producto que todos los tipos de objetos constructores tienen en común.

  2. Los Constructores Concretos ofrecen distintas implementaciones de los pasos de construcción. Los constructores concretos pueden crear productos que no siguen la interfaz común.

  3. Los Productos son los objetos resultantes. Los productos construidos por distintos objetos constructores no tienen que pertenecer a la misma jerarquía de clases o interfaz.

  4. La clase Directora define el orden en el que se invocarán los pasos de construcción, por lo que puedes crear y reutilizar configuraciones específicas de los productos.

  5. El Cliente debe asociar uno de los objetos constructores con la clase directora. Normalmente, se hace una sola vez mediante los parámetros del constructor de la clase directora, que utiliza el objeto constructor para el resto de la construcción. No obstante, existe una solución alternativa para cuando el cliente pasa el objeto constructor al método de producción de la clase directora. En este caso, puedes utilizar un constructor diferente cada vez que produzcas algo con la clase directora.

Cómo implementarlo

Asegúrate de poder definir claramente los pasos comunes de construcción para todas las representaciones disponibles del producto. De lo contrario, no podrás proceder a implementar el patrón.

Declara estos pasos en la interfaz constructora base.

Crea una clase constructora concreta para cada una de las representaciones de producto e implementa sus pasos de construcción.

No olvides implementar un método para extraer el resultado de la construcción. La razón por la que este método no se puede declarar dentro de la interfaz constructora es que varios constructores pueden construir productos sin una interfaz común. Por lo tanto, no sabemos cuál será el tipo de retorno para un método como éste. No obstante, si trabajas con productos de una única jerarquía, el método de extracción puede añadirse sin problemas a la interfaz base.

Piensa en crear una clase directora. Puede encapsular varias formas de construir un producto utilizando el mismo objeto constructor.

El código cliente crea tanto el objeto constructor como el director. Antes de que empiece la construcción, el cliente debe pasar un objeto constructor al director. Normalmente, el cliente hace esto sólo una vez, mediante los parámetros del constructor del director. El director utiliza el objeto constructor para el resto de la construcción. Existe una manera alternativa, en la que el objeto constructor se pasa directamente al método de construcción del director.

El resultado de la construcción tan solo se puede obtener directamente del director si todos los productos siguen la misma interfaz. De lo contrario, el cliente deberá extraer el resultado del constructor.

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


class Builder(ABC):
    """
    La interfaz Builder especifica métodos para crear las diferentes partes de
    los objetos Producto.
    """

    @abstractproperty
    def product(self) -> None:
        pass

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

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

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


class AceroBuilder(Builder):
    """
    Las clases de constructores concretos siguen la interfaz del constructor y proporcionan
    implementaciones específicas de los pasos de construcción. Tu programa puede tener
    Varias variaciones de Builders, implementadas de manera diferente.
    """

    def __init__(self) -> None:
        """
        Una instancia de generador nueva debe contener un objeto de producto en blanco, que es
        utilizado en el montaje posterior.
        """
        self.reset()

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

    @property
    def product(self) -> Product1:
 
        product = self._product
        self.reset()
        return product

    def produce_part_a(self) -> None:
        self._product.add("Carroceria")

    def produce_part_b(self) -> None:
        self._product.add("Pertas")

    def produce_part_c(self) -> None:
        self._product.add("Tapa frontal o Capó")


class Product1():

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

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

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


class Director:

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

    @property
    def builder(self) -> Builder:
        return self._builder

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

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

    def build_full_featured_product(self) -> None:
        self.builder.produce_part_a()
        self.builder.produce_part_b()
        self.builder.produce_part_c()


if __name__ == "__main__":
    director = Director()
    builder = AceroBuilder()
    director.builder = builder

    print("Produccion de carroseria: ")
    director.build_minimal_viable_product()
    builder.product.list_parts()

    print("\n")

    print("Produccion  final ")
    director.build_full_featured_product()
    builder.product.list_parts()

    print("\n")

    print("Creacion de partes perzonalizada: ")
    builder.produce_part_a()
    builder.produce_part_b()
    builder.product.list_parts()