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.

© Copyright 2024. Todos los derechos reservados