Introducción

El patrón de diseño Builder es un patrón creacional que permite la construcción de objetos complejos paso a paso. A diferencia de otros patrones creacionales que construyen productos en una sola operación, el patrón Builder permite que el proceso de construcción se divida en múltiples pasos y se pueda personalizar de manera flexible.

Objetivos del Patrón Builder

  • Separar la construcción de un objeto complejo de su representación: Permite crear diferentes representaciones del mismo objeto.
  • Facilitar la creación de objetos complejos: Simplifica la creación de objetos que requieren múltiples pasos de configuración.

Estructura del Patrón Builder

El patrón Builder generalmente se compone de los siguientes componentes:

  1. Builder: Declara una interfaz para crear partes del objeto Product.
  2. ConcreteBuilder: Implementa la interfaz Builder y construye partes específicas del producto.
  3. Product: Representa el objeto complejo que se está construyendo.
  4. Director: Construye un objeto utilizando la interfaz Builder.

Ejemplo Práctico

Vamos a ilustrar el patrón Builder con un ejemplo práctico en el que construimos una Pizza.

Paso 1: Definir el Producto

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}'

Paso 2: Crear la Interfaz Builder

from abc import ABC, abstractmethod

class PizzaBuilder(ABC):
    @abstractmethod
    def set_dough(self):
        pass

    @abstractmethod
    def set_sauce(self):
        pass

    @abstractmethod
    def set_topping(self):
        pass

    @abstractmethod
    def get_pizza(self):
        pass

Paso 3: Implementar el ConcreteBuilder

class HawaiianPizzaBuilder(PizzaBuilder):
    def __init__(self):
        self.pizza = Pizza()

    def set_dough(self):
        self.pizza.dough = 'cross'

    def set_sauce(self):
        self.pizza.sauce = 'mild'

    def set_topping(self):
        self.pizza.topping = 'ham+pineapple'

    def get_pizza(self):
        return self.pizza

Paso 4: Crear el Director

class Cook:
    def __init__(self, builder):
        self._builder = builder

    def construct_pizza(self):
        self._builder.set_dough()
        self._builder.set_sauce()
        self._builder.set_topping()

    def get_pizza(self):
        return self._builder.get_pizza()

Paso 5: Uso del Patrón Builder

if __name__ == "__main__":
    hawaiian_pizza_builder = HawaiianPizzaBuilder()
    cook = Cook(hawaiian_pizza_builder)
    cook.construct_pizza()
    pizza = cook.get_pizza()
    print(pizza)

Explicación del Código

  1. Producto (Pizza): La clase Pizza representa el objeto complejo que queremos construir.
  2. Interfaz Builder (PizzaBuilder): Define los métodos necesarios para construir las partes de la Pizza.
  3. ConcreteBuilder (HawaiianPizzaBuilder): Implementa los métodos de la interfaz PizzaBuilder para construir una pizza específica.
  4. Director (Cook): Utiliza el Builder para construir el objeto Pizza paso a paso.

Ejercicio Práctico

Ejercicio 1: Crear una Pizza Vegana

  1. Definir una nueva clase VeganPizzaBuilder que implemente PizzaBuilder.
  2. Implementar los métodos set_dough, set_sauce, set_topping y get_pizza.
  3. Utilizar la clase Cook para construir una pizza vegana y mostrarla por pantalla.

Solución

class VeganPizzaBuilder(PizzaBuilder):
    def __init__(self):
        self.pizza = Pizza()

    def set_dough(self):
        self.pizza.dough = 'whole wheat'

    def set_sauce(self):
        self.pizza.sauce = 'tomato'

    def set_topping(self):
        self.pizza.topping = 'bell peppers+olives'

    def get_pizza(self):
        return self.pizza

if __name__ == "__main__":
    vegan_pizza_builder = VeganPizzaBuilder()
    cook = Cook(vegan_pizza_builder)
    cook.construct_pizza()
    pizza = cook.get_pizza()
    print(pizza)

Retroalimentación sobre Errores Comunes

  • Olvidar inicializar el producto en el constructor del ConcreteBuilder: Asegúrate de inicializar self.pizza en el constructor.
  • No implementar todos los métodos de la interfaz Builder: Verifica que todos los métodos abstractos estén implementados en el ConcreteBuilder.
  • No utilizar el Director correctamente: Asegúrate de llamar a construct_pizza antes de obtener el producto con get_pizza.

Conclusión

El patrón Builder es una herramienta poderosa para la construcción de objetos complejos de manera controlada y flexible. Permite separar la lógica de construcción de la representación del objeto, facilitando la creación de diferentes variantes del mismo producto. En el siguiente módulo, exploraremos los patrones estructurales, comenzando con una introducción a su propósito y uso.

© Copyright 2024. Todos los derechos reservados