Padrão de Projeto Flyweight: Otimizando o Uso de Memória com Compartilhamento de Objetos

O padrão Flyweight é um padrão de projeto estrutural focado na eficiência de memória. Seu objetivo principal é reduzir o consumo de recursos ao lidar com um grande volume de objetos similares, compartilhando o máximo de dados possível entre eles em vez de manter todos os dados em cada objeto individualmente.

Conceitos Fundamentias: Estado Intrínseco e Extrínseco

A implementação eficaz do Flyweight baseia-se na distinção entre dois tipos de dados:

  • Estado Intrínseco: Informações constantes que podem ser compartilhadas entre vários objetos. Este estado é armazenado dentro do objeto Flyweight.
  • Estado Extrínseco: Informações que variam dependendo do contexto e não podem ser compartilahdas. Este estado deve ser passado ao objeto via parâmetros quando necessário.

Componentes do Padrão

  1. Flyweight Abstrato: Define a interface através da qual os flyweights podem receber e atuar sobre o estado extrínseco.
  2. Flyweight Concreto: Implementa a interface e armazena o estado intrínseco.
  3. Fábrica Flyweight (Factory): Gerencia o pool de objetos. Quando um cliente solicita um objeto, a fábrica verifica se ele já existe; se sim, retorna a instância existente; caso contrário, cria uma nova.

Exemplo Prático: Sistema de Renderização de Peças

Imagine um jogo estilo Tetris. Criar milhares de instâncias de cada bloco pode sobrecarregar a memória. Usaremos o Flyweight para gerenciar as formas dos blocos como estados intrínsecos.

// Flyweight Abstrato
public abstract class FormaBase {
    public abstract String getTipo();

    public void renderizar(String cor) {
        System.out.println("Bloco: " + getTipo() + " | Cor: " + cor);
    }
}

// Flyweights Concretos
public class BlocoT extends FormaBase {
    @Override
    public String getTipo() {
        return "Formato T";
    }
}

public class BlocoZ extends FormaBase {
    @Override
    public String getTipo() {
        return "Formato Z";
    }
}

// Fábrica Flyweight com Singleton
public class GerenciadorDeBlocos {
    private final Map<String, FormaBase> blocos = new HashMap<>();

    private GerenciadorDeBlocos() {}

    private static class Holder {
        private static final GerenciadorDeBlocos INSTANCIA = new GerenciadorDeBlocos();
    }

    public static GerenciadorDeBlocos getInstancia() {
        return Holder.INSTANCIA;
    }

    public FormaBase buscarBloco(String chave) {
        if (!blocos.containsKey(chave)) {
            switch (chave) {
                case "T": blocos.put("T", new BlocoT()); break;
                case "Z": blocos.put("Z", new BlocoZ()); break;
            }
        }
        return blocos.get(chave);
    }
}

Vantagens e Desvantagens

Vantagens

  • Redução significativa da pegada de memória em aplicações com muitos objetos semelhantes.
  • Melhoria na performance global do sistema ao evitar alocações excessivas.

Desvantagens

  • Aumenta a complexidade do código ao separar os estados.
  • Pode haver uma pequena perda de tempo de processamento ao calcular ou passar o estado extrínseco.

Análise de Uso no JDK: A Classe Integer

O Java utiliza o Flyweight internamente na classe Integer através do método valueOf(). Existe um cache para números pequenos, o que evita a criação de novos objetos desnecessariamente.

public class TesteCache {
    public static void main(String[] args) {
        Integer a = 100;
        Integer b = 100;
        // true: Ambos apontam para a mesma instância no cache
        System.out.println("a == b? " + (a == b));

        Integer x = 200;
        Integer y = 200;
        // false: Fora do intervalo padrão de cache (-128 a 127)
        System.out.println("x == y? " + (x == y));
    }
}

Ao analisar o código fonte da classe Integer, observamos a implementação do IntegerCache:

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

Este mecanismo garante que valores frequentemente utilizados sejam reutilizados, economizando memória e tempo de execução, o que é a essência do padrão Flyweight.

Tags: design patterns Flyweight java memory optimization Software Architecture

Publicado em 7-5 23:23