O padrão Flyweight é um padrão de design estrutural que tem como objetivo principal reduzir a quantidade de memória utilizada por um programa ao compartilhar o máximo possível de dados entre objetos similares.

Ele é particularmente útil em situações onde um grande número de objetos com estados similares é necessário, e seu uso pode resultar em uma significativa economia de recursos. O Flyweight resolve problemas como:

  1. Alto Consumo de Memória: Em sistemas onde muitas instâncias de uma classe são criadas, e estas instâncias têm muitos dados em comum, o uso de memória pode ser excessivo. O Flyweight permite compartilhar esses dados comuns entre múltiplas instâncias.

  2. Eficiência em Sistemas com Muitos Objetos: Em cenários como gráficos, jogos ou simulações, onde milhares ou milhões de objetos podem ser necessários, o Flyweight permite que o sistema maneje essa quantidade sem esgotar os recursos de memória.

  3. Compartilhamento de Estado Intrínseco: O padrão distingue entre estados intrínsecos (internos) e extrínsecos (externos). Estados intrínsecos são compartilhados e independentes do contexto, enquanto estados extrínsecos são específicos para cada objeto e não são compartilhados.

Como Funciona

O padrão Flyweight utiliza uma fábrica (Flyweight Factory) que gerencia os objetos Flyweight compartilhados. Quando um cliente solicita um Flyweight, a fábrica retorna uma instância existente ou cria uma nova se necessário. Os objetos Flyweight são imutáveis: uma vez criados, seu estado intrínseco não muda.

Exemplo

Um exemplo clássico é o uso do Flyweight em um processador de texto para representar caracteres. Cada caractere pode ter atributos como fonte, tamanho e cor (estado extrínseco), mas o caractere em si (por exemplo, ‘A’) é compartilhado (estado intrínseco). Em vez de criar um novo objeto para cada ocorrência de ‘A’, o programa usa um único objeto Flyweight para todas as ocorrências de ‘A’, alterando apenas os atributos extrínsecos conforme necessário.

Exemplo de implementação

Vamos criar um exemplo simples do padrão Flyweight em Java. Vamos supor que estamos desenvolvendo um aplicativo de pintura onde muitos círculos de diferentes cores e tamanhos podem ser desenhados.

Para economizar memória, usaremos o padrão Flyweight para compartilhar objetos de cor, que é o estado intrínseco, enquanto o tamanho e a localização do círculo, que são estados extrínsecos, serão armazenados separadamente.

Definindo a Interface Flyweight

interface Cor {
    void aplicarCor();
}

Implementando as Cores Concretas (Concrete Flyweights)

class CorVermelha implements Cor {
    @Override
    public void aplicarCor() {
        System.out.println("Aplicando cor vermelha.");
    }
}
 
class CorAzul implements Cor {
    @Override
    public void aplicarCor() {
        System.out.println("Aplicando cor azul.");
    }
}

Implementando a Fábrica Flyweight

import java.util.HashMap;
import java.util.Map;
 
class FabricaDeCores {
    private static final Map<String, Cor> cores = new HashMap<>();
 
    public static Cor getCor(String nomeCor) {
        Cor cor = cores.get(nomeCor);
 
        if (cor == null) {
            switch (nomeCor) {
                case "Vermelho":
                    cor = new CorVermelha();
                    break;
                case "Azul":
                    cor = new CorAzul();
                    break;
                // Adicione mais cores conforme necessário
            }
            cores.put(nomeCor, cor);
        }
        return cor;
    }
}

Classe Círculo (Contexto Flyweight)

class Circulo {
    private final Cor cor; // Estado intrínseco
    private int x, y, raio; // Estado extrínseco
 
    public Circulo(Cor cor) {
        this.cor = cor;
    }
 
    public void definirLocalizacaoETamanho(int x, int y, int raio) {
        this.x = x;
        this.y = y;
        this.raio = raio;
    }
 
    public void desenhar() {
        cor.aplicarCor();
        System.out.println("Desenhando um círculo na posição [" + x + ", " + y + "] com raio " + raio);
    }
}

Utilizando o Padrão Flyweight

public class Main {
    public static void main(String[] args) {
        Cor vermelho = FabricaDeCores.getCor("Vermelho");
        Cor azul = FabricaDeCores.getCor("Azul");
 
        Circulo circulo1 = new Circulo(vermelho);
        circulo1.definirLocalizacaoETamanho(10, 10, 5);
        circulo1.desenhar();
 
        Circulo circulo2 = new Circulo(azul);
        circulo2.definirLocalizacaoETamanho(20, 30, 10);
        circulo2.desenhar();
 
        Circulo circulo3 = new Circulo(vermelho);
        circulo3.definirLocalizacaoETamanho(5, 5, 3);
        circulo3.desenhar();
    }
}