Saltar al contenido

Flyweight

Un patrón estructural para tener más objetos en memoria, compartiendo entre ellos el estado que se repite.

6 min. de lectura

Flyweight es un patrón estructural que permite mantener más objetos en memoria compartiendo la parte de su estado que es común entre muchos de ellos.

El problema

La página de categoría “Trekking” de AndesShop muestra miles de productos en simultáneo, y cada tarjeta de producto puede llevar una o más etiquetas visuales — “Nuevo”, “Oferta”, “Últimas unidades”. Si cada tarjeta crea su propio objeto Badge con el ícono, el color y el texto de la etiqueta, terminás con miles de objetos que contienen exactamente los mismos tres datos repetidos (“Oferta” siempre es el mismo ícono, el mismo color naranja, el mismo texto) — la única diferencia real entre tarjetas es a qué producto pertenece cada una.

La solución

Flyweight separa el estado de un objeto en dos partes: el estado intrínseco, que es idéntico entre muchas instancias y se puede compartir (el ícono, color y texto de “Oferta”), y el estado extrínseco, que es propio de cada uso puntual (a qué producto pertenece, en qué posición se muestra) y que el código cliente pasa como parámetro en el momento de usarlo. Una fábrica se encarga de devolver siempre el mismo objeto compartido para un mismo estado intrínseco, en vez de crear uno nuevo cada vez.

Estructura de Flyweight: el estado intrínseco vive una sola vez en el flyweight compartido; el extrínseco lo aporta cada contexto en la llamada.

Ejemplo en Java

// Flyweight: contiene solo el estado intrínseco, compartido entre muchos productos
class BadgeStyle {
    private final String icon;
    private final String color;
    private final String label;

    public BadgeStyle(String icon, String color, String label) {
        this.icon = icon;
        this.color = color;
        this.label = label;
    }

    // El estado extrínseco (productSku) llega como parámetro, no se guarda acá
    public String render(String productSku) {
        return icon + " " + label + " (" + productSku + ")";
    }
}

// Factory: garantiza una única instancia de BadgeStyle por tipo
class BadgeFactory {
    private final Map<String, BadgeStyle> cache = new HashMap<>();

    public BadgeStyle getBadge(String type) {
        return cache.computeIfAbsent(type, t -> switch (t) {
            case "OFFER" -> new BadgeStyle("🏷️", "orange", "Oferta");
            case "NEW" -> new BadgeStyle("", "blue", "Nuevo");
            default -> throw new IllegalArgumentException("Unknown badge type: " + t);
        });
    }
}
// Client code: miles de tarjetas de producto, un puñado de instancias de BadgeStyle
BadgeFactory factory = new BadgeFactory();
for (Product product : catalogPage) {
    BadgeStyle badge = factory.getBadge("OFFER"); // misma instancia para todas las ofertas
    System.out.println(badge.render(product.getSku()));
}

Cuándo usarlo

  • Cuando tenés una cantidad muy grande de objetos que comparten buena parte de su estado, y eso está consumiendo memoria de forma notoria.
  • Cuando ese estado compartido se puede separar limpiamente del estado que sí varía por instancia.

Cuándo evitarlo

Con una cantidad moderada de objetos, o cuando el estado compartible es chico frente al que varía, el ahorro de memoria no compensa la complejidad extra de separar estado intrínseco y extrínseco.

Ventajas y desventajas

VentajasDesventajas
Reduce significativamente el uso de memoria cuando hay muchísimas instancias similaresEl código gana complejidad al separar estado intrínseco y extrínseco
Centraliza el estado compartido en un solo lugarEl estado extrínseco tiene que recalcularse o pasarse cada vez, lo que puede costar tiempo de CPU a cambio de memoria

Relación con otros patrones

  • Suele combinarse con Facade o una fábrica dedicada que oculta el proceso de compartir instancias.
  • Se diferencia de Singleton en que Flyweight comparte muchas instancias distintas (una por cada combinación de estado intrínseco), no una única instancia global.

Te sirvió, compartilo

// ¿te sirvió?
// compartilo