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:
- Builder: Declara una interfaz para crear partes del objeto
Product
. - ConcreteBuilder: Implementa la interfaz
Builder
y construye partes específicas del producto. - Product: Representa el objeto complejo que se está construyendo.
- 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
- Producto (
Pizza
): La clasePizza
representa el objeto complejo que queremos construir. - Interfaz Builder (
PizzaBuilder
): Define los métodos necesarios para construir las partes de laPizza
. - ConcreteBuilder (
HawaiianPizzaBuilder
): Implementa los métodos de la interfazPizzaBuilder
para construir una pizza específica. - Director (
Cook
): Utiliza elBuilder
para construir el objetoPizza
paso a paso.
Ejercicio Práctico
Ejercicio 1: Crear una Pizza Vegana
- Definir una nueva clase
VeganPizzaBuilder
que implementePizzaBuilder
. - Implementar los métodos
set_dough
,set_sauce
,set_topping
yget_pizza
. - 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 inicializarself.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 elConcreteBuilder
. - No utilizar el
Director
correctamente: Asegúrate de llamar aconstruct_pizza
antes de obtener el producto conget_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.
Curso de Patrones de Diseño de Software
Módulo 1: Introducción a los Patrones de Diseño
- ¿Qué son los Patrones de Diseño?
- Historia y Origen de los Patrones de Diseño
- Clasificación de los Patrones de Diseño
- Ventajas y Desventajas de Usar Patrones de Diseño
Módulo 2: Patrones Creacionales
- Introducción a los Patrones Creacionales
- Singleton
- Factory Method
- Abstract Factory
- Builder
- Prototype
Módulo 3: Patrones Estructurales
Módulo 4: Patrones de Comportamiento
- Introducción a los Patrones de Comportamiento
- Chain of Responsibility
- Command
- Interpreter
- Iterator
- Mediator
- Memento
- Observer
- State
- Strategy
- Template Method
- Visitor
Módulo 5: Aplicación de Patrones de Diseño
- Cómo Seleccionar el Patrón Adecuado
- Ejemplos Prácticos de Uso de Patrones
- Patrones de Diseño en Proyectos Reales
- Refactorización Usando Patrones de Diseño
Módulo 6: Patrones de Diseño Avanzados
- Patrones de Diseño en Arquitecturas Modernas
- Patrones de Diseño en Microservicios
- Patrones de Diseño en Sistemas Distribuidos
- Patrones de Diseño en Desarrollo Ágil