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.