π What Youβll Learn
- What the Flyweight Pattern is
- Why and when to use it
- How to implement it in Java
- Real-world analogies
- Common pitfalls and best practices
π What Is the Flyweight Pattern?
The Flyweight Pattern is used to minimize memory usage by sharing as much data as possible with similar objects. Itβs all about reusing existing instances instead of creating new ones.
Think about characters in a text editor: the letter 'a' appears thousands of times, but we don't need thousands of separate 'a' objects β just one shared one.
π§© When to Use It
Apply the Flyweight Pattern when:
- You have lots of objects that consume a lot of memory
- Many of those objects are similar or identical
- You need to optimize performance and reduce memory footprint
π§± Java Implementation
πΌοΈ Step 1: Create the Flyweight Interface
public interface Shape {
void draw();
}
π΅ Step 2: Concrete Flyweight Objects
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;
}
public void draw() {
System.out.println("Drawing a " + color + " circle at (" + x + "," + y + ") with radius " + radius);
}
}
π Step 3: Flyweight Factory
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 a " + color + " circle");
}
return circle;
}
}
β Usage
public class FlyweightDemo {
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() {
String[] colors = {"Red", "Green", "Blue", "White", "Black"};
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);
}
}
π Real-World Analogy
- Text editors reuse objects for each letter typed, avoiding millions of repeated object instances.
- Game development: trees, rocks, and houses often share models and textures to save memory.
β οΈ Pitfalls to Avoid
- β Using Flyweight where itβs unnecessary β itβs not always worth the added complexity
- β Managing shared and unique state improperly (distinguish between intrinsic and extrinsic state carefully)
- β Making Flyweight objects mutable when they should be immutable
β Best Practices
- Keep shared (intrinsic) state inside the flyweight object
- Pass unique (extrinsic) state externally when needed
- Document the use of the Flyweight to avoid confusion later
π Recap
- The Flyweight Pattern minimizes memory usage by sharing objects
- Best used when dealing with large numbers of similar objects
- Separates shared state from unique state
- Real-world examples: text editors, graphics engines, object pooling