Vandaag zullen we de Flyweight-ontwerppatroon bekijken.
Flyweight Ontwerppatroon
Volgens GoF is het doel van het flyweight-ontwerppatroon:
Gebruik delen om efficiënt grote aantallen fijnkorrelige objecten te ondersteunen
Het flyweight-ontwerppatroon is een Structureel ontwerppatroon zoals het Facade-patroon, Adapter-patroon en Decorator-patroon. Het flyweight-ontwerppatroon wordt gebruikt wanneer we veel objecten van een klasse moeten maken. Aangezien elk object geheugenruimte verbruikt die cruciaal kan zijn voor apparaten met weinig geheugen, zoals mobiele apparaten of ingebedde systemen, kan het flyweight-ontwerppatroon worden toegepast om de belasting van het geheugen te verminderen door objecten te delen. Voordat we het flyweight-ontwerppatroon toepassen, moeten we de volgende factoren overwegen:
- Het aantal objecten dat door de toepassing moet worden gemaakt, moet groot zijn.
- Objectcreatie legt een zware belasting op het geheugen en kan ook tijdrovend zijn.
- De objecteigenschappen kunnen worden onderverdeeld in intrinsieke en extrinsieke eigenschappen, extrinsieke eigenschappen van een object moeten worden gedefinieerd door het clientprogramma.
Om het flyweight-patroon toe te passen, moeten we de eigenschappen van het object verdelen in intrinsieke en extrinsieke eigenschappen. Intrinsieke eigenschappen maken het object uniek, terwijl extrinsieke eigenschappen worden ingesteld door clientcode en worden gebruikt om verschillende bewerkingen uit te voeren. Bijvoorbeeld, een cirkelobject kan extrinsieke eigenschappen hebben zoals kleur en breedte. Om het flyweight-patroon toe te passen, moeten we een Flyweight-fabriek maken die gedeelde objecten retourneert. Voor ons voorbeeld stellen we dat we een tekening moeten maken met lijnen en ovalen. Dus we zullen een interface Shape
hebben en de concrete implementaties ervan als Line
en Oval
. De Oval-klasse zal een intrinsieke eigenschap hebben om te bepalen of de ovaal moet worden gevuld met een gegeven kleur of niet, terwijl de Line-klasse geen intrinsieke eigenschap zal hebben.
Flyweight Design Pattern Interface en Concrete Klassen
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");
//vertraging toevoegen
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 {
//intrinsieke eigenschap
private boolean fill;
public Oval(boolean f){
this.fill=f;
System.out.println("Creating Oval object with fill="+f);
//vertraging toevoegen
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);
}
}
}
Merk op dat ik opzettelijk vertraging heb geïntroduceerd bij het maken van het object van concrete klassen om aan te tonen dat het flyweight-patroon kan worden gebruikt voor objecten die veel tijd in beslag nemen bij instantiatie.
Flyweight-fabriek
De flyweight-fabriek wordt gebruikt door clientprogramma’s om het object te instantiëren, dus we moeten een kaart van objecten in de fabriek bijhouden die niet toegankelijk mag zijn voor de clienttoepassing. Telkens wanneer het clientprogramma een oproep doet om een instantie van een object te krijgen, moet deze uit de HashMap worden teruggegeven. Als het niet wordt gevonden, maak dan een nieuw object en plaats het in de kaart en geef het vervolgens terug. We moeten ervoor zorgen dat alle intrinsieke eigenschappen worden overwogen bij het maken van het object. Onze flyweight-fabrieksklasse ziet eruit als de onderstaande code. 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;
}
}
Let op het gebruik van Java Enum voor typeveiligheid, Java Composition (vormenkaart) en Factory-patroon in de methode getShape
.
Voorbeeld van een client voor het Vlieggewicht Ontwerppatroon
Hieronder staat een voorbeeldprogramma dat gebruikmaakt van de implementatie van het vlieggewichtpatroon. 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
Dat is alles voor het vlieggewichtpatroon, we zullen in toekomstige berichten meer ontwerppatronen bekijken. Als je het leuk vond, deel dan je gedachten in de opmerkingensectie en deel het ook met anderen.
Voorbeeld van het Vlieggewicht Ontwerppatroon in JDK
Alle wrapperklassen gebruiken de methode valueOf()
om gecachte objecten te tonen die het gebruik van het Vlieggewicht ontwerppatroon laten zien. Het beste voorbeeld is de Java String klasse met de implementatie van de String Pool.
Belangrijke punten van het Vlieggewicht Ontwerppatroon
- In ons voorbeeld wordt de clientcode niet gedwongen om objecten te maken met behulp van de Flyweight-fabriek, maar we kunnen dat afdwingen om ervoor te zorgen dat de clientcode de implementatie van het vlieggewichtpatroon gebruikt, maar het is een volledige ontwerpbeslissing voor een specifieke toepassing.
- Het vlieggewichtpatroon introduceert complexiteit en als het aantal gedeelde objecten groot is, is er een afweging tussen geheugen en tijd, dus we moeten het verstandig gebruiken op basis van onze vereisten.
- De implementatie van het vlieggewichtpatroon is niet nuttig wanneer het aantal intrinsieke eigenschappen van het object groot is, waardoor de implementatie van de fabrieksklasse complex wordt.
Dat is alles voor het Vlieggewicht ontwerppatroon in Java.
Source:
https://www.digitalocean.com/community/tutorials/flyweight-design-pattern-java