Patrón creacional Builder(Python) - fapaccha/Dise-o-dirigido-por-el-modelo GitHub Wiki
Builder(Python)
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
-
La interfaz Constructora declara pasos de construcción de producto que todos los tipos de objetos constructores tienen en común.
-
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.
-
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.
-
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.
-
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()