Patrón Factory dinámico en Java

Advertisements

El patrón Factory es un patrón de diseño creacional ampliamente utilizado en Java. Sin embargo, su implementación clásica presenta un defecto importante: infringe el principio de Open/Closed del diseño SOLID. Cada vez que se necesita añadir un nuevo tipo e implementación, la clase Factory debe modificarse.

Presentamos Java 8, con sus potentes expresiones lambda y la interfaz funcional Supplier. Esto nos permite crear un Patrón de Fábrica Dinámica más flexible y extensible, manteniendo nuestra clase de fábrica cerrada a modificaciones y abierta a extensiones.

The Problem with Classic Factory Pattern

Comencemos con un ejemplo utilizando el patrón Factory clásico.

Advertisements
interface Shape {
    void draw();
}

class Circle implements Shape {
    public void draw() {
        System.out.println("Drawing a Circle");
    }
}

class Square implements Shape {
    public void draw() {
        System.out.println("Drawing a Square");
    }
}

class ShapeFactory {
    public static Shape createShape(String type) {
        switch (type) {
            case "circle": return new Circle();
            case "square": return new Square();
            default: throw new IllegalArgumentException("Unknown shape: " + type);
        }
    }
}

Desventajas

  • Violación del principio Open/Closed: Cada nueva implementación required de mofidificar la clase Factory, en este caso ShapeFactory.
  • Difícil de escalar: Con el tiempo, la fábrica se convierte en una gran central monolítica.
  • Díficil de probar y mantener.

Factory dinámica con Lambdas y Supplier

Java 8 introdujo la interfaz Supplier, ideal para las fábricas. Representa una función que proporciona una instancia del tipo T. Vamos a ver como construir una fábrica dinámica que permita el registro de nuevos tipos en tiempo de ejecución, evitando así cambios en la propia fábrica.

1. Definir la interface y sus implementaciones

interface Shape {
    void draw();
}

class Circle implements Shape {
    public void draw() {
        System.out.println("Drawing a Circle");
    }
}

class Square implements Shape {
    public void draw() {
        System.out.println("Drawing a Square");
    }
}

2. Crear el Dynamic Factory

import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;

class DynamicShapeFactory {
    private final Map<String, Supplier<Shape>> registry = new HashMap<>();

    public void registerShape(String shapeName, Supplier<Shape> supplier) {
        registry.put(shapeName.toLowerCase(), supplier);
    }

    public Shape createShape(String shapeName) {
        Supplier<Shape> supplier = registry.get(shapeName.toLowerCase());
        if (supplier != null) {
            return supplier.get();
        }
        throw new IllegalArgumentException("Unknown shape: " + shapeName);
    }
}

3. Ejemplo de Uso

public class Main {
    public static void main(String[] args) {
        DynamicShapeFactory factory = new DynamicShapeFactory();

        // Register shapes
        factory.registerShape("circle", Circle::new);
        factory.registerShape("square", Square::new);

        // Create shapes dynamically
        Shape shape1 = factory.createShape("circle");
        Shape shape2 = factory.createShape("square");

        shape1.draw(); // Output: Drawing a Circle
        shape2.draw(); // Output: Drawing a Square
    }
}

Beneficios del Patrón Factory dinámico

  • Se adhiere al principio Open/Closed: se pueden agregar nuevas formas sin modificar DynamicShapeFactory.
  • Extensible en tiempo de ejecución: puede cargar y registrar nuevos tipos incluso a través de archivos de configuración o inyección de dependencia.
  • Más fácil de probar: puedes simular o crear fábricas provisionales proporcionando proveedores personalizados en escenarios de prueba.

Conclusiones

El Patrón de Fábrica Dinámica en Java, habilitado por lambdas y Supplier, es una alternativa limpia, elegante y moderna al enfoque de fábrica clásico. Favorece una mejor arquitectura de software al reducir el acoplamiento, aumentar la flexibilidad y adoptar los principios SOLID.

Si bien puede introducir una ligera complejidad inicial debido a la lógica de registro, los beneficios a largo plazo, especialmente en aplicaciones escalables y modulares, lo convierten en una poderosa opción de diseño.

Referencias

Advertisements

Leave a Reply

Your email address will not be published. Required fields are marked *