Introducción
El patrón Abstract Factory es uno de los patrones creacionales más utilizados en el diseño de software. Este patrón proporciona una interfaz para crear familias de objetos relacionados o dependientes sin especificar sus clases concretas. Es especialmente útil cuando el sistema debe ser independiente de cómo se crean, componen y representan los productos.
Conceptos Clave
- Abstract Factory: Declara una interfaz para operaciones que crean productos abstractos.
- Concrete Factory: Implementa las operaciones para crear objetos concretos.
- Abstract Product: Declara una interfaz para un tipo de objeto producto.
- Concrete Product: Define un objeto producto que implementa la interfaz de Abstract Product.
- Client: Utiliza únicamente las interfaces declaradas por Abstract Factory y Abstract Product.
Diagrama UML
+---------------------+ | AbstractFactory | +---------------------+ | + createProductA() | | + createProductB() | +---------------------+ ^ | +---------------------+ | ConcreteFactory1 | +---------------------+ | + createProductA() | | + createProductB() | +---------------------+ ^ | +---------------------+ +---------------------+ | AbstractProductA | | AbstractProductB | +---------------------+ +---------------------+ ^ ^ | | +---------------------+ +---------------------+ | ConcreteProductA1 | | ConcreteProductB1 | +---------------------+ +---------------------+
Ejemplo Práctico
Vamos a implementar un ejemplo práctico en Python para ilustrar cómo funciona el patrón Abstract Factory. Imaginemos que estamos creando una aplicación que necesita trabajar con diferentes tipos de botones y checkboxes para diferentes sistemas operativos (Windows y Mac).
Paso 1: Definir las Interfaces Abstractas
from abc import ABC, abstractmethod # Abstract Product A class Button(ABC): @abstractmethod def paint(self): pass # Abstract Product B class Checkbox(ABC): @abstractmethod def paint(self): pass # Abstract Factory class GUIFactory(ABC): @abstractmethod def create_button(self) -> Button: pass @abstractmethod def create_checkbox(self) -> Checkbox: pass
Paso 2: Implementar los Productos Concretos
# Concrete Product A1 class WindowsButton(Button): def paint(self): print("Render a button in Windows style") # Concrete Product A2 class MacButton(Button): def paint(self): print("Render a button in Mac style") # Concrete Product B1 class WindowsCheckbox(Checkbox): def paint(self): print("Render a checkbox in Windows style") # Concrete Product B2 class MacCheckbox(Checkbox): def paint(self): print("Render a checkbox in Mac style")
Paso 3: Implementar las Fábricas Concretas
# Concrete Factory 1 class WindowsFactory(GUIFactory): def create_button(self) -> Button: return WindowsButton() def create_checkbox(self) -> Checkbox: return WindowsCheckbox() # Concrete Factory 2 class MacFactory(GUIFactory): def create_button(self) -> Button: return MacButton() def create_checkbox(self) -> Checkbox: return MacCheckbox()
Paso 4: Implementar el Cliente
class Application: def __init__(self, factory: GUIFactory): self.factory = factory self.button = self.factory.create_button() self.checkbox = self.factory.create_checkbox() def paint(self): self.button.paint() self.checkbox.paint()
Paso 5: Uso del Cliente
def main(): for os_type in ["Windows", "Mac"]: if os_type == "Windows": factory = WindowsFactory() else: factory = MacFactory() app = Application(factory) app.paint() if __name__ == "__main__": main()
Ejercicio Práctico
Ejercicio 1
Implementa una nueva familia de productos para Linux. Debes crear las clases LinuxButton
y LinuxCheckbox
, así como la fábrica LinuxFactory
.
Solución
# Concrete Product A3 class LinuxButton(Button): def paint(self): print("Render a button in Linux style") # Concrete Product B3 class LinuxCheckbox(Checkbox): def paint(self): print("Render a checkbox in Linux style") # Concrete Factory 3 class LinuxFactory(GUIFactory): def create_button(self) -> Button: return LinuxButton() def create_checkbox(self) -> Checkbox: return LinuxCheckbox()
Ejercicio 2
Modifica el método main
para incluir la opción de crear una interfaz gráfica para Linux.
Solución
def main(): for os_type in ["Windows", "Mac", "Linux"]: if os_type == "Windows": factory = WindowsFactory() elif os_type == "Mac": factory = MacFactory() else: factory = LinuxFactory() app = Application(factory) app.paint() if __name__ == "__main__": main()
Conclusión
El patrón Abstract Factory es una herramienta poderosa para crear familias de objetos relacionados sin acoplar el código a sus clases concretas. Esto permite que el sistema sea más flexible y fácil de extender. En este módulo, hemos aprendido cómo implementar este patrón y cómo aplicarlo en un ejemplo práctico. Ahora estamos listos para explorar otros patrones creacionales en el siguiente tema.
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