Flyweight pattern

The Flyweight Pattern is mainly used to reduce the number of objects created, thereby reducing memory usage and improving performance. This type of design pattern belongs to structural patterns; it provides a way to reduce the number of objects and thus improve the object structure required by the application.

The Flyweight pattern attempts to reuse existing objects of the same type; if no matching object is found, it creates a new object. We will demonstrate this pattern by drawing 20 circles distributed at different positions using 5 objects. Since there are only 5 available colors, the color attribute is used to check the existing ones.CircleObject.

summary

intent

Reduce memory consumption when creating a large number of similar objects by sharing objects.

Main problem solved

  • Avoid memory overflow problems caused by creating a large number of objects.
  • Improve memory usage efficiency by sharing objects.

Use Case

  • When there are a large number of similar or identical objects in the system.
  • The cost of creating and destroying objects is high.
  • The state of objects can be externalized, that is, part of the object's state can exist independently of the object itself.

Implementation Approach

  • Define the Flyweight interface: Create a flyweight interface that defines the state that can be shared.
  • Create concrete Flyweight classes: A concrete class that implements this interface and contains internal state.
  • Use the Flyweight factory: Create a factory class to manage the creation and reuse of flyweight objects.

Key code

  • HashMap: Use a hash table to store created flyweight objects for fast retrieval.

Application example

  1. String objects in Java.: Strings that already exist in the string constant pool are reused.
  2. Database connection pool: Database connections are reused to avoid frequent creation and destruction of connections.

Advantages

  • Reduce memory consumption: By sharing objects, the number of objects in memory is reduced.
  • Improve Efficiency: Reduces object creation time and improves system efficiency.

Disadvantages

  • Increase system complexity: It is necessary to separate internal state and external state, which increases the complexity of design and implementation.
  • Thread safety issues: If external state is not handled properly, it may cause thread safety issues.

Usage suggestions

  • Consider using the Flyweight Pattern when creating a large number of similar objects.
  • Ensure that the internal state of flyweight objects is shared, while the external state is independent of the object.

Notes

  • State separation: Clearly distinguish internal state from external state to avoid confusion.
  • Flyweight factory: Use a flyweight factory to control object creation and reuse, ensuring object consistency and integrity.

Structure

The Flyweight Pattern includes the following core roles:

  • Flyweight Factory:

    • Responsible for creating and managing flyweight objects, usually containing a pool (cache) for storing and reusing created flyweight objects.
  • Concrete Flyweight:

    • Implements the abstract flyweight interface and contains internal state and external state. The internal state can be shared, while the external state is passed by the client.
  • Abstract Flyweight:

    • Defines the interface for concrete flyweights and non-shared flyweights, usually including methods for setting external state.
  • Client:

    • Uses the flyweight factory to obtain flyweight objects and operates on flyweight objects by setting external state. Clients usually do not need to care about the specific implementation of flyweight objects.

Implementation

We will create aShapeinterface and implementationShapeentity classes of the interfaceCircleThe next step is to define the factory class.ShapeFactory。

ShapeFactoryThere is aCircleofHashMap, where the key name isCircleThe color of the object. Whenever a request is received, a circle of a specific color is created.ShapeFactoryCheck itsHashMapThe circle object in the hashmap, if foundCircleobject, then return that object; otherwise, create a new object stored in the hashmap for later use, and return it to the client.

FlyWeightPatternDemoClass usageShapeFactoryTo obtainShapeobject. It willShapeFactoryPass Information (red / green / blue/ black / white), in order to obtain the color of the object it needs.

享元模式的 UML 图

Step 1

create an interface.

Shape.java

public interface Shape { void draw(); }

Step 2

Create concrete classes that implement the interface.

Circle.java

public class Circle implements Shape { private String color; private int x; private int y; private int radius; public Circle(String color){ this.color = color; } public void setX(int x) { this.x = x; } public void setY(int y) { this.y = y; } public void setRadius(int radius) { this.radius = radius; } @Override public void draw() { System.out.println("Circle: Draw() [Color : " + color +", x : " + x +", y :" + y +", radius :" + radius); } }

Step 3

Create a factory that generates objects of entity classes based on given information.

ShapeFactory.java

import java.util.HashMap; public class ShapeFactory { private static final HashMap<String, Shape> circleMap = new HashMap<>(); public static Shape getCircle(String color) { Circle circle = (Circle)circleMap.get(color); if(circle == null) { circle = new Circle(color); circleMap.put(color, circle); System.out.println("Creating circle of color : " + color); } return circle; } }

Step 4

Use this factory to obtain entity class objects by passing color information.

FlyweightPatternDemo.java

public class FlyweightPatternDemo { private static final String colors[] = { "Red", "Green", "Blue", "White", "Black" }; public static void main(String[] args) { for(int i=0; i < 20; ++i) { Circle circle = (Circle)ShapeFactory.getCircle(getRandomColor()); circle.setX(getRandomX()); circle.setY(getRandomY()); circle.setRadius(100); circle.draw(); } } private static String getRandomColor() { return colors[(int)(Math.random()*colors.length)]; } private static int getRandomX() { return (int)(Math.random()*100 ); } private static int getRandomY() { return (int)(Math.random()*100); } }

Step 5

Run the program, output result:

Creating circle of color : Black
Circle: Draw() [Color : Black, x : 36, y :71, radius :100
Creating circle of color : Green
Circle: Draw() [Color : Green, x : 27, y :27, radius :100
Creating circle of color : White
Circle: Draw() [Color : White, x : 64, y :10, radius :100
Creating circle of color : Red
Circle: Draw() [Color : Red, x : 15, y :44, radius :100
Circle: Draw() [Color : Green, x : 19, y :10, radius :100
Circle: Draw() [Color : Green, x : 94, y :32, radius :100
Circle: Draw() [Color : White, x : 69, y :98, radius :100
Creating circle of color : Blue
Circle: Draw() [Color : Blue, x : 13, y :4, radius :100
Circle: Draw() [Color : Green, x : 21, y :21, radius :100
Circle: Draw() [Color : Blue, x : 55, y :86, radius :100
Circle: Draw() [Color : White, x : 90, y :70, radius :100
Circle: Draw() [Color : Green, x : 78, y :3, radius :100
Circle: Draw() [Color : Green, x : 64, y :89, radius :100
Circle: Draw() [Color : Blue, x : 3, y :91, radius :100
Circle: Draw() [Color : Blue, x : 62, y :82, radius :100
Circle: Draw() [Color : Green, x : 97, y :61, radius :100
Circle: Draw() [Color : Green, x : 86, y :12, radius :100
Circle: Draw() [Color : Green, x : 38, y :93, radius :100
Circle: Draw() [Color : Red, x : 76, y :82, radius :100
Circle: Draw() [Color : Blue, x : 95, y :82, radius :100
other extensions