Hoje vamos analisar o padrão de design Flyweight. `
Padrão de Design Flyweight
`De acordo com o GoF, a intenção do `padrão de design flyweight` é: `
`Utilizar o compartilhamento para suportar eficientemente um grande número de objetos de granularidade fina. `
`O padrão de design Flyweight é um `padrão de design estrutural`, assim como o `padrão de fachada`, o `padrão de adaptador` e o `padrão de decorador`. Ele é utilizado quando precisamos criar muitos objetos de uma classe. Como cada objeto consome espaço de memória, o que pode ser crucial para dispositivos com pouca memória, como dispositivos móveis ou sistemas embarcados, o padrão de design Flyweight pode ser aplicado para reduzir a carga na memória compartilhando objetos. Antes de aplicarmos o padrão de design Flyweight, precisamos considerar os seguintes fatores: `
- `O número de objetos a serem criados pela aplicação deve ser grande. `
- `A criação de objetos consome muita memória e pode ser demorada também.
- As propriedades do objeto podem ser divididas em propriedades intrínsecas e extrínsecas, as propriedades extrínsecas de um Objeto devem ser definidas pelo programa cliente.
Para aplicar o padrão de peso mosca, precisamos dividir as propriedades do Objeto em propriedades intrínsecas e extrínsecas. Propriedades intrínsecas tornam o Objeto único, enquanto as propriedades extrínsecas são definidas pelo código do cliente e são usadas para realizar operações diferentes. Por exemplo, um Objeto Círculo pode ter propriedades extrínsecas, como cor e largura. Para aplicar o padrão de peso mosca, precisamos criar uma fábrica de peso mosca que retorna os objetos compartilhados. Para o nosso exemplo, digamos que precisamos criar um desenho com linhas e Ovais. Assim, teremos uma interface Shape
e suas implementações concretas como Line
e Oval
. A classe Oval terá uma propriedade intrínseca para determinar se deve preencher o Oval com uma cor fornecida ou não, enquanto a Linha não terá nenhuma propriedade intrínseca.
Interface e Classes Concretas do Padrão de Projeto Peso Mosca
Shape.java
package com.journaldev.design.flyweight;
import java.awt.Color;
import java.awt.Graphics;
public interface Shape {
public void draw(Graphics g, int x, int y, int width, int height,
Color color);
}
Line.java
package com.journaldev.design.flyweight;
import java.awt.Color;
import java.awt.Graphics;
public class Line implements Shape {
public Line(){
System.out.println("Creating Line object");
//adicionando atraso de tempo
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void draw(Graphics line, int x1, int y1, int x2, int y2,
Color color) {
line.setColor(color);
line.drawLine(x1, y1, x2, y2);
}
}
Oval.java
package com.journaldev.design.flyweight;
import java.awt.Color;
import java.awt.Graphics;
public class Oval implements Shape {
//propriedade intrínseca
private boolean fill;
public Oval(boolean f){
this.fill=f;
System.out.println("Creating Oval object with fill="+f);
//adicionando atraso de tempo
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void draw(Graphics circle, int x, int y, int width, int height,
Color color) {
circle.setColor(color);
circle.drawOval(x, y, width, height);
if(fill){
circle.fillOval(x, y, width, height);
}
}
}
Observe que eu intencionalmente introduzi um atraso na criação do objeto das classes concretas para destacar que o padrão de flyweight pode ser usado para objetos que levam muito tempo para serem instanciados.
Factory de Flyweight
A fábrica de flyweight será usada pelos programas clientes para instanciar o objeto, então precisamos manter um mapa de objetos na fábrica que não deve ser acessível pelo aplicativo cliente. Sempre que o programa cliente faz uma chamada para obter uma instância do objeto, ela deve ser retornada do HashMap, se não encontrada, então criar um novo objeto e colocá-lo no Mapa e depois retorná-lo. Precisamos garantir que todas as propriedades intrínsecas sejam consideradas ao criar o objeto. Nossa classe de fábrica de flyweight parece o código abaixo. ShapeFactory.java
package com.journaldev.design.flyweight;
import java.util.HashMap;
public class ShapeFactory {
private static final HashMap<ShapeType,Shape> shapes = new HashMap<ShapeType,Shape>();
public static Shape getShape(ShapeType type) {
Shape shapeImpl = shapes.get(type);
if (shapeImpl == null) {
if (type.equals(ShapeType.OVAL_FILL)) {
shapeImpl = new Oval(true);
} else if (type.equals(ShapeType.OVAL_NOFILL)) {
shapeImpl = new Oval(false);
} else if (type.equals(ShapeType.LINE)) {
shapeImpl = new Line();
}
shapes.put(type, shapeImpl);
}
return shapeImpl;
}
public static enum ShapeType{
OVAL_FILL,OVAL_NOFILL,LINE;
}
}
Observe o uso de Enum do Java para segurança de tipo, Composição do Java (mapa de formas) e Padrão de Fábrica no método getShape
.
Exemplo de Cliente de Padrão de Projeto Flyweight
Abaixo está um programa de exemplo que consome a implementação do padrão flyweight. DrawingClient.java
package com.journaldev.design.flyweight;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import com.journaldev.design.flyweight.ShapeFactory.ShapeType;
public class DrawingClient extends JFrame{
private static final long serialVersionUID = -1350200437285282550L;
private final int WIDTH;
private final int HEIGHT;
private static final ShapeType shapes[] = { ShapeType.LINE, ShapeType.OVAL_FILL,ShapeType.OVAL_NOFILL };
private static final Color colors[] = { Color.RED, Color.GREEN, Color.YELLOW };
public DrawingClient(int width, int height){
this.WIDTH=width;
this.HEIGHT=height;
Container contentPane = getContentPane();
JButton startButton = new JButton("Draw");
final JPanel panel = new JPanel();
contentPane.add(panel, BorderLayout.CENTER);
contentPane.add(startButton, BorderLayout.SOUTH);
setSize(WIDTH, HEIGHT);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
Graphics g = panel.getGraphics();
for (int i = 0; i < 20; ++i) {
Shape shape = ShapeFactory.getShape(getRandomShape());
shape.draw(g, getRandomX(), getRandomY(), getRandomWidth(),
getRandomHeight(), getRandomColor());
}
}
});
}
private ShapeType getRandomShape() {
return shapes[(int) (Math.random() * shapes.length)];
}
private int getRandomX() {
return (int) (Math.random() * WIDTH);
}
private int getRandomY() {
return (int) (Math.random() * HEIGHT);
}
private int getRandomWidth() {
return (int) (Math.random() * (WIDTH / 10));
}
private int getRandomHeight() {
return (int) (Math.random() * (HEIGHT / 10));
}
private Color getRandomColor() {
return colors[(int) (Math.random() * colors.length)];
}
public static void main(String[] args) {
DrawingClient drawing = new DrawingClient(500,600);
}
}
I have used random number generation to generate different type of Shapes in our frame. If you run above client program, you will notice the delay in creating first Line Object and Oval objects with fill as true and false. After that the program executes quickly since its using the shared objects. After clicking “Draw” button multiple times, the frame looks like below image. And you will see following output in command line confirming that Objects are shared.
Creating Line object
Creating Oval object with fill=true
Creating Oval object with fill=false
Isso é tudo para o padrão flyweight, vamos explorar mais padrões de design em futuras postagens. Se você gostou, compartilhe seus pensamentos na seção de comentários e compartilhe também com outras pessoas.
Exemplo de Padrão de Projeto Flyweight no JDK
Todas as classes de invólucro método valueOf()
usam objetos em cache, mostrando o uso do padrão de design Flyweight. O melhor exemplo é a implementação da classe String Java no Pool de Strings.
Pontos Importantes do Padrão de Design Flyweight
- No nosso exemplo, o código do cliente não é obrigado a criar objetos usando a fábrica Flyweight, mas podemos forçar isso para garantir que o código do cliente utilize a implementação do padrão flyweight, mas é uma decisão de design completa para uma aplicação específica.
- O padrão Flyweight introduz complexidade e, se o número de objetos compartilhados for grande, haverá um equilíbrio entre memória e tempo, então precisamos usá-lo criteriosamente com base nos nossos requisitos.
- A implementação do padrão Flyweight não é útil quando o número de propriedades intrínsecas do objeto é grande, tornando a implementação da classe Factory complexa.
Isso é tudo para o padrão de design Flyweight em Java.
Source:
https://www.digitalocean.com/community/tutorials/flyweight-design-pattern-java