Padrão Flyweight em Java

Padrão Flyweight em Java

1. Visão geral

Neste artigo, daremos uma olhada no padrão de design flyweight. Esse padrão é usado para reduzir o espaço ocupado pela memória. Também pode melhorar o desempenho em aplicativos onde a instanciação de objetos é cara.

Simplificando, o padrão flyweight é baseado em uma fábrica que recicla objetos criados armazenando-os após a criação. Cada vez que um objeto é solicitado, a fábrica procura o objeto para verificar se ele já foi criado. Se houver, o objeto existente será retornado - caso contrário, um novo será criado, armazenado e retornado.

O estado do objeto flyweight é feito de um componente invariável compartilhado com outros objetos semelhantes (intrinsic) e um componente variante que pode ser manipulado pelo código do cliente (extrinsic).

É muito importante que os objetos flyweight sejam imutáveis: qualquer operação no estado deve ser realizada pela fábrica.

2. Implementação

Os principais elementos do padrão são:

  • uma interface que define as operações que o código do cliente pode executar no objeto flyweight

  • uma ou mais implementações concretas da nossa interface

  • uma fábrica para lidar com instanciação e cache de objetos

Vamos ver como implementar cada componente.

2.1. Interface do Veículo

Para começar, criaremos uma interfaceVehicle. Como essa interface será o tipo de retorno do método de fábrica, precisamos expor todos os métodos relevantes:

public void start();
public void stop();
public Color getColor();

2.2. Veículo de concreto

Em seguida, vamos fazer uma classeCar como umVehicle. concreto. Nosso carro implementará todos os métodos da interface do veículo. Quanto ao seu estado, terá um motor e um campo de cores:

private Engine engine;
private Color color;

2.3. Fábrica de Veículos

Por último, mas não menos importante, criaremos oVehicleFactory. Construir um veículo novo é uma operação muito cara, portanto a fábrica criará apenas um veículo por cor.

Para fazer isso, mantemos o controle dos veículos criados usando um mapa como um cache simples:

private static Map vehiclesCache
  = new HashMap<>();

public static Vehicle createVehicle(Color color) {
    Vehicle newVehicle = vehiclesCache.computeIfAbsent(color, newColor -> {
        Engine newEngine = new Engine();
        return new Car(newEngine, newColor);
    });
    return newVehicle;
}

Observe como o código do cliente só pode afetar o estado extrínseco do objeto (a cor do nosso veículo) passando-o como um argumento para o métodocreateVehicle.

3. Casos de Uso

3.1. Compressão de dados

O objetivo do padrão flyweight é reduzir o uso de memória compartilhando o máximo de dados possível, portanto, é uma boa base para algoritmos de compressão sem perdas. Nesse caso, cada objeto flyweight age como um ponteiro com seu estado extrínseco sendo a informação dependente do contexto.

Um exemplo clássico desse uso está em um processador de texto. Aqui, cada caractere é um objeto flyweight que compartilha os dados necessários para a renderização. Como resultado, apenas a posição do caractere dentro do documento ocupa memória adicional.

3.2. Cache de Dados

Muitos aplicativos modernos usam caches para melhorar o tempo de resposta. O padrão flyweight é semelhante ao conceito principal de um cache e pode ser adequado a esse propósito.

Obviamente, existem algumas diferenças importantes em complexidade e implementação entre esse padrão e um cache típico de uso geral.

4. Conclusão

Para resumir, este tutorial rápido se concentrou no padrão de design flyweight em Java. Também verificamos alguns dos cenários mais comuns que envolvem o padrão.

Todo o código dos exemplos está disponível emthe GitHub project.