concept
Flyweight Pattern is a shared way to reuse a large number of fine-grained objects to reduce memory usage (to avoid creating and destroying objects in large amounts repeatedly).
The Flyweight in the name is one of the weight levels in a fight match. It is known in Chinese as the fly weight or the next lightest weight.Porting this word into software engineering is also used to represent very small objects, that is, fine-grained objects.Thus, the feature of the share mode is not only sharing, but also the fine-grained sharing.
Internal state, external state, enjoyment pool
The same content that can be shared in the enjoyment class is called the internal state, and the specific content that needs to be set by the external environment is called the external state. They are independent, decoupled, and combined to form the enjoyment class.Different but related (such as the same class) enjoyment objects are aggregated to form an enjoyment pool that is maintained using an enjoyment factory.
This calls the enjoyment factory (in its maintained enjoyment pool) to get the desired enjoyment object and configure its external state for use as required.
Because internal and external states are distinguished, different external states can be set to make the same object have some different characteristics, while the same internal state can be shared.Therefore, the essence of the hedonic mode is to decouple complete objects into finer granularity, decouple and unchange them, and share them unchanged, so as to reduce the number of objects and save memory.
The hedonic model refers to the sharing of the single-case model and the unified supply of the factory model, which is characterized by the reuse of fine-grained objects.
The difference from the singleton pattern is that fine-grained reuse does not reuse complete objects.
Role & UML
Abstract enjoyment class Specific Enjoyment Class FlyweightFactory Client
Demo: Editor Picture Reuse - Java
Requirements:
Enjoyment mode is used extensively in editor software, for example, when the same picture appears multiple times in a document, you only need to create a picture object, which can be repeated multiple times in different places by setting where the picture appears in the application.
UML:
Code structure:
./ ├── Client.java ├── ImageNodeFactory.java ├── flyweight │ ├── BirdImage.java │ ├── ImageNode.java │ ├── TreeImage.java │ ├── bird.jpeg │ └── tree.jpg └── result.pdf
Here, PDF editing uses the itextpdf package.Pom.xmlConfiguration in
<dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.13</version> </dependency>
ImageNode <Interface>: Abstract enjoyment class
package homework.Flyweight.flyweight; import com.itextpdf.text.BadElementException; import com.itextpdf.text.Image; import java.io.IOException; public interface ImageNode { // Returns a picture (internal state) object wrapped with coordinates (external state < parameters) public Image getImageInPdf(int x, int y) throws IOException, BadElementException; }
BirdImage <Class>: specific enjoyment class
package homework.Flyweight.flyweight; import com.itextpdf.text.BadElementException; import com.itextpdf.text.Image; import javax.imageio.ImageIO; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; public class BirdImage implements ImageNode { // The internal state of the enjoyment maintenance (pictures, sharing) private byte[] image; // Load Internal Status (Picture) public BirdImage() throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ImageIO.write( ImageIO.read(new File("src/main/java/homework/Flyweight/flyweight/bird.jpeg")), "jpeg", baos); this.image = baos.toByteArray(); } @Override public Image getImageInPdf(int x, int y) throws IOException, BadElementException { Image imageInPdf = Image.getInstance(this.image); // Internal Status (Picture Object) + External Status (Picture Location) imageInPdf.scaleAbsolute(30, 30); imageInPdf.setAbsolutePosition(x, y); // Print the address of the picture in memory System.out.println(this.image); return imageInPdf; } }
TreeImage <Class>: specific enjoyment class
package homework.Flyweight.flyweight; import com.itextpdf.text.BadElementException; import com.itextpdf.text.Image; import javax.imageio.ImageIO; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; public class TreeImage implements ImageNode { // The internal state of the enjoyment maintenance (pictures, sharing) private byte[] image; // Load Internal Status (Picture) public TreeImage() throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ImageIO.write( ImageIO.read(new File("src/main/java/homework/Flyweight/flyweight/tree.jpg")), "jpg", baos); this.image = baos.toByteArray(); } @Override public Image getImageInPdf(int x, int y) throws IOException, BadElementException { Image imageInPdf = Image.getInstance(image); // Internal Status (Picture Object) + External Status (Picture Location) imageInPdf.scaleAbsolute(30, 30); imageInPdf.setAbsolutePosition(x, y); // Print the address of the picture in memory System.out.println(this.image); return imageInPdf; } }
ImageNodeFactory <Class>: Heyuan Factory
package homework.Flyweight; import homework.Flyweight.flyweight.BirdImage; import homework.Flyweight.flyweight.ImageNode; import homework.Flyweight.flyweight.TreeImage; import java.io.IOException; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class ImageNodeFactory { // Heyuan Pool maintained by Heyuan Factory private static Map<String, ImageNode> imagePool = new ConcurrentHashMap<>(); // Get your share public static ImageNode getImageNode(String type) throws IOException { if(!imagePool.containsKey(type)) { switch (type) { case "bird": imagePool.put(type, new BirdImage()); break; case "tree": imagePool.put(type, new TreeImage()); break; } } return imagePool.get(type); } }
Client <Class>: Client
package homework.Flyweight; import com.itextpdf.text.*; import com.itextpdf.text.pdf.PdfWriter; import homework.Flyweight.flyweight.ImageNode; import java.io.*; public class Client { public static void main(String[] args) throws IOException, DocumentException { // 1. Initialize PDF Rectangle rectangle = new Rectangle(PageSize.A4); // Set PDF paper rectangle with A4 size rectangle.setBackgroundColor(BaseColor.WHITE); // Set Background Color // Create a document object with initialization size and margins Document document = new Document(rectangle, 10, 10, 10, 10); // Top, bottom, left, right page spacing String pdfPath = "src/main/java/homework/Flyweight/result.pdf"; // Output location of PDF PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(pdfPath)); document.open(); // Open Document Object // 2. Insert pictures in PDF for(int i=0; i<10; i++){ ImageNode imageNode = ImageNodeFactory.getImageNode("tree"); // Picture coordinates (external state) are maintained by the client document.add(imageNode.getImageInPdf(10*i,100*i)); System.out.println("Object ImageNode: "+imageNode); } document.close(); // close document } }
Console Printing:
[B@16b4a017 Object ImageNode: homework.Flyweight.flyweight.TreeImage@5ecddf8f [B@16b4a017 Object ImageNode: homework.Flyweight.flyweight.TreeImage@5ecddf8f [B@16b4a017 Object ImageNode: homework.Flyweight.flyweight.TreeImage@5ecddf8f [B@16b4a017 Object ImageNode: homework.Flyweight.flyweight.TreeImage@5ecddf8f [B@16b4a017 Object ImageNode: homework.Flyweight.flyweight.TreeImage@5ecddf8f [B@16b4a017 Object ImageNode: homework.Flyweight.flyweight.TreeImage@5ecddf8f [B@16b4a017 Object ImageNode: homework.Flyweight.flyweight.TreeImage@5ecddf8f [B@16b4a017 Object ImageNode: homework.Flyweight.flyweight.TreeImage@5ecddf8f [B@16b4a017 Object ImageNode: homework.Flyweight.flyweight.TreeImage@5ecddf8f [B@16b4a017 Object ImageNode: homework.Flyweight.flyweight.TreeImage@5ecddf8f Process finished with exit code 0
Generated PDF:
Reference
- https://www.jianshu.com/p/f9997c0c2a55
- Enjoyment mode - Lianliankan picture sharing https://blog.csdn.net/ABAP_Brave/article/details/78528416
- Viewing Design Mode with JDK Source --- Enjoyment Mode