Heute werden wir uns das Flyweight-Designmuster ansehen.
Das Flyweight-Designmuster
Nach GoF ist die Absicht des Flyweight-Designmusters:
Verwenden Sie das Teilen, um große Mengen von feinkörnigen Objekten effizient zu unterstützen
Das Flyweight-Designmuster ist ein strukturelles Designmuster wie das Fassadenmuster, das Adaptermuster und das Dekorationsmuster. Das Flyweight-Designmuster wird verwendet, wenn wir viele Objekte einer Klasse erstellen müssen. Da jedes Objekt Speicherplatz verbraucht, der für Geräte mit geringem Speicher, wie Mobilgeräte oder eingebettete Systeme, entscheidend sein kann, kann das Flyweight-Designmuster angewendet werden, um die Belastung des Speichers durch das Teilen von Objekten zu verringern. Bevor wir das Flyweight-Designmuster anwenden, müssen wir folgende Faktoren berücksichtigen:
- Die Anzahl der von der Anwendung zu erstellenden Objekte sollte enorm sein.
- Die Erstellung von Objekten ist speicherintensiv und kann auch zeitaufwendig sein.
- Die Objekteigenschaften können in intrinsische und extrinsische Eigenschaften unterteilt werden, extrinsische Eigenschaften eines Objekts sollten vom Clientprogramm definiert werden.
Um das Fliegengewichtsmuster anzuwenden, müssen wir die Objekteigenschaft in intrinsische und extrinsische Eigenschaften aufteilen. Intrinsische Eigenschaften machen das Objekt einzigartig, während extrinsische Eigenschaften vom Clientcode festgelegt werden und zur Durchführung verschiedener Operationen verwendet werden. Zum Beispiel kann ein Objekt „Kreis“ extrinsische Eigenschaften wie Farbe und Breite haben. Um das Fliegengewichtsmuster anzuwenden, müssen wir eine „Fliegengewichtsfabrik“ erstellen, die die gemeinsam genutzten Objekte zurückgibt. Für unser Beispiel nehmen wir an, dass wir eine Zeichnung mit Linien und Ovalen erstellen müssen. Daher haben wir eine Schnittstelle „Shape“ und ihre konkreten Implementierungen als „Line“ und „Oval“. Die Klasse „Oval“ wird eine intrinsische Eigenschaft haben, um zu bestimmen, ob das Oval mit einer bestimmten Farbe gefüllt werden soll oder nicht, während „Line“ keine intrinsische Eigenschaft hat.
Schnittstellen und konkrete Klassen des Fliegengewichtsmusters
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");
//Hinzufügen einer Zeitverzögerung
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 {
//intrinsische Eigenschaft
private boolean fill;
public Oval(boolean f){
this.fill=f;
System.out.println("Creating Oval object with fill="+f);
//Hinzufügen einer Zeitverzögerung
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);
}
}
}
Beachten Sie, dass ich absichtlich Verzögerungen bei der Erstellung des Objekts der konkreten Klassen eingeführt habe, um zu verdeutlichen, dass das Fliegengewichtsmuster für Objekte verwendet werden kann, die beim Instanziieren viel Zeit in Anspruch nehmen.
Fliegengewichtsfabrik
Die Fliegengewichtsfabrik wird von Clientprogrammen verwendet, um das Objekt zu instanziieren, daher müssen wir eine Abbildung der Objekte in der Fabrik führen, die von der Clientanwendung nicht zugänglich sein sollten. Immer wenn das Clientprogramm einen Aufruf zum Abrufen einer Instanz des Objekts macht, sollte es aus der HashMap zurückgegeben werden. Wenn es nicht gefunden wird, wird ein neues Objekt erstellt und in die Map eingefügt und dann zurückgegeben. Wir müssen sicherstellen, dass alle intrinsischen Eigenschaften beim Erstellen des Objekts berücksichtigt werden. Unsere Fliegengewichtsfabrikklasse sieht wie folgt aus. 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;
}
}
Beachten Sie die Verwendung von Java Enum für Typsicherheit, Java-Komposition (Formenmappe) und Factory-Muster in der Methode getShape
.
Beispiel für den Client des Fliegengewicht-Entwurfsmusters
Unten finden Sie ein Beispielprogramm, das die Implementierung des Fliegengewichtsmusters verwendet. 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
Das ist alles zum Fliegengewichtsmuster, wir werden in zukünftigen Beiträgen weitere Entwurfsmuster betrachten. Wenn es Ihnen gefallen hat, teilen Sie bitte Ihre Gedanken im Kommentarbereich mit und teilen Sie es auch mit anderen.
Beispiel für das Fliegengewicht-Entwurfsmuster in JDK
Alle Wrapper-Klassen verwenden die valueOf()
-Methode, um zwischengespeicherte Objekte zu zeigen, die das Fliegengewicht-Entwurfsmuster verwenden. Das beste Beispiel ist die Implementierung der Java String-Klasse des String Pools.
Wichtige Punkte des Fliegengewichts-Entwurfsmusters
- In unserem Beispiel wird der Client-Code nicht gezwungen, Objekte mit dem Flyweight-Fabrik zu erstellen, aber wir können das erzwingen, um sicherzustellen, dass der Client-Code die Implementierung des Fliegengewichtsmusters verwendet, aber es ist eine vollständige Designentscheidung für eine bestimmte Anwendung.
- Das Fliegengewichtsmuster führt Komplexität ein, und wenn die Anzahl der gemeinsam genutzten Objekte groß ist, besteht ein Kompromiss zwischen Speicher und Zeit, daher müssen wir es basierend auf unseren Anforderungen sorgfältig einsetzen.
- Die Implementierung des Fliegengewichtsmusters ist nicht nützlich, wenn die Anzahl der intrinsischen Eigenschaften des Objekts groß ist, was die Implementierung der Fabrikklasse komplex macht.
Das ist alles zum Fliegengewicht-Entwurfsmuster in Java.
Source:
https://www.digitalocean.com/community/tutorials/flyweight-design-pattern-java