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:
passPaso 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
