Flyweight Pattern
# Flyweight Pattern
## Flyweight Pattern
The Flyweight Pattern is primarily used to reduce the number of objects created, thereby reducing memory usage and improving performance. This type of design pattern is a structural pattern that provides a way to improve the object structure required by the application by reducing the number of objects.
The Flyweight Pattern attempts to reuse existing similar objects. If no matching object is found, a new object is created. We will demonstrate this pattern by creating 5 objects to draw 20 circles at different positions. Since only 5 colors are available, the `color` property is used to check for existing `_Circle_` objects.
### Intent
To reduce memory consumption when creating a large number of similar objects by sharing objects.
### Problems Solved
* Avoids memory overflow issues caused by creating a large number of objects.
* Improves memory usage efficiency through object sharing.
### Use Cases
* When the system contains a large number of similar or identical objects.
* When the cost of creating and destroying objects is high.
* When the object's state can be externalized, meaning part of the object's state can exist independently of the object itself.
### Implementation Approach
* **Define the Flyweight Interface**: Create a flyweight interface that specifies the state that can be shared.
* **Create Concrete Flyweight Classes**: Concrete classes that implement the interface, containing the internal state.
* **Use a Flyweight Factory**: Create a factory class to manage the creation and reuse of flyweight objects.
### Key Code
* **HashMap**: Use a hash table to store already created flyweight objects for quick retrieval.
### Application Examples
1. **String Objects in Java**: Strings that already exist in the string constant pool are reused.
2. **Database Connection Pools**: Database connections are reused to avoid frequent creation and destruction of connections.
### Advantages
* **Reduces Memory Consumption**: By sharing objects, the number of objects in memory is reduced.
* **Improves Efficiency**: Reduces the time spent creating objects, thereby improving system efficiency.
### Disadvantages
* **Increases System Complexity**: Requires separating internal state from external state, adding complexity to design and implementation.
* **Thread Safety Issues**: If external state is not handled properly, it may cause thread safety problems.
### Usage Recommendations
* 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 between internal state and 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. It typically contains a pool (cache) for storing and reusing already created flyweight objects.
* **Concrete Flyweight:**
* Implements the abstract flyweight interface and contains both internal and external states. The internal state is shareable, while the external state is passed by the client.
* **Abstract Flyweight (Flyweight):**
* Defines the interface for concrete flyweights and non-shared flyweights. It usually includes methods for setting external state.
* **Client:**
* Uses the flyweight factory to obtain flyweight objects and manipulates them by setting external state. The client typically does not need to care about the specific implementation of flyweight objects.
We will create a `_Shape_` interface and a concrete class `_Circle_` that implements the `_Shape_` interface. The next step is to define the factory class `_ShapeFactory_`.
`_ShapeFactory_` has a `_HashMap_` of `_Circle_` objects, where the key is the color of the `_Circle_` object. Whenever a request is received, a circle of a specific color is created. `_ShapeFactory_` checks its `_HashMap_` for a circle object of that color. If a `_Circle_` object is found, it is returned; otherwise, a new object is created, stored in the hashmap for future use, and returned to the client.
The `_FlyWeightPatternDemo_` class uses `_ShapeFactory_` to obtain `_Shape_` objects. It passes information (`_red / green / blue/ black / white`) to `_ShapeFactory_` to get the color of the object it needs.

### Step 1
Create an interface.
## Shape.java
```java
public interface Shape {
void draw();
}
### Step 2
Create concrete classes implementing the interface.
## Circle.java
```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 to generate objects of given information using entity classes.
## ShapeFactory.java
```java
import java.util.HashMap;
public class ShapeFactory {
private static final HashMap 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 the factory to get entities by passing color information.
## FlyweightPatternDemo.java
```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
Execute the program, output the 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
YouTip