The Flyweight Design Pattern: Share to Save Memory
Master the Flyweight Pattern in Java with real-world examples. Learn to support thousands of objects efficiently by sharing common state across instances.
Moshiour Rahman
The Problem: Memory Explosion
Imagine a game with 1 million trees. Each tree has:
- Intrinsic state (shared):
treeType,texture,model(2MB each) - Extrinsic state (unique):
x,ycoordinates (8 bytes)
Naive approach:
1 million trees × 2MB = 2,000 GB of RAM 💥
But there are only 5 tree types. Why store the same texture 200,000 times?
The Solution: The Flyweight Pattern
The Flyweight Pattern minimizes memory by sharing as much data as possible with similar objects.
Real-Life Analogy: Chess Pieces ♟️
In a chess game:
- Shared (Intrinsic): Icon image, movement rules (same for all white pawns)
- Unique (Extrinsic): Current position on board
Instead of storing the icon 8 times for 8 pawns, share one icon and store only positions.
Visualizing the Pattern

Implementation
1. The Flyweight Class (Immutable Shared Object)
// Flyweight: Stores intrinsic (shared) state
public class TreeType {
private final String name;
private final String color;
private final String texture; // Large data (2MB)
public TreeType(String name, String color, String texture) {
this.name = name;
this.color = color;
this.texture = texture;
}
public void render(int x, int y) {
System.out.println("Rendering " + name + " at (" + x + ", " + y + ")");
// Use shared texture
}
}
2. The Flyweight Factory (Pool)
import java.util.HashMap;
import java.util.Map;
public class TreeFactory {
private static final Map<String, TreeType> treeTypes = new HashMap<>();
public static TreeType getTreeType(String name, String color, String texture) {
String key = name + color;
if (!treeTypes.containsKey(key)) {
treeTypes.put(key, new TreeType(name, color, texture));
System.out.println("Created new TreeType: " + key);
}
return treeTypes.get(key);
}
}
3. Context Object (Stores Extrinsic State)
// Context: Stores extrinsic (unique) state
public class Tree {
private int x, y; // Unique
private TreeType type; // Shared (flyweight)
public Tree(int x, int y, TreeType type) {
this.x = x;
this.y = y;
this.type = type;
}
public void render() {
type.render(x, y); // Pass extrinsic state
}
}
Usage
TreeFactory factory = new TreeFactory();
// Create 1 million trees with only 5 tree types
List<Tree> forest = new ArrayList<>();
for (int i = 0; i < 1_000_000; i++) {
int x = random.nextInt(10000);
int y = random.nextInt(10000);
String[] types = {"Oak", "Pine", "Birch", "Maple", "Spruce"};
String treeType = types[random.nextInt(5)];
TreeType sharedType = TreeFactory.getTreeType(treeType, "Green", "texture.png");
forest.add(new Tree(x, y, sharedType));
}
// Memory used:
// - 5 TreeType objects (5 × 2MB = 10MB)
// - 1M Tree objects (1M × 16 bytes = 16MB)
// Total: ~26MB instead of 2,000GB!
In The Wild (Real World Examples)
1. String Pool in Java
The most famous flyweight!
String s1 = "Hello"; // Goes to string pool
String s2 = "Hello"; // Reuses from pool
System.out.println(s1 == s2); // true (same object!)
2. Integer.valueOf() Cache
Java caches integers from -128 to 127:
Integer a = Integer.valueOf(100);
Integer b = Integer.valueOf(100);
System.out.println(a == b); // true (cached)
Integer c = Integer.valueOf(200);
Integer d = Integer.valueOf(200);
System.out.println(c == d); // false (not cached, different objects)
3. Font Rendering
GUI frameworks share font objects:
Font arial12 = FontFactory.getFont("Arial", 12);
// Same font object used for all "Arial 12" text
When to Use Flyweight
✅ Use when:
- Large number of similar objects
- Most state can be extrinsic (pulled out)
- Object identity doesn’t matter
❌ Don’t use when:
- Few objects
- No shared state
- Object identity is important (need unique instances)
Cheat Sheet
| Feature | Details |
|---|---|
| Category | Structural |
| Problem Solved | Memory overhead from large numbers of objects |
| Key implementation | Factory pool + intrinsic/extrinsic state separation |
| Pros | Memory savings (massive reduction for many objects) |
| Cons | Complexity (state separation), CPU tradeoff (some overhead) |
Tips to Remember 🧠
- “String Pool”: The #1 example every Java developer knows.
- “Intrinsic = Inside, Extrinsic = External”: Intrinsic is shared inside flyweight, extrinsic is passed from outside.
- “Factory Pattern”: Flyweight almost always uses a factory to manage the pool.
Moshiour Rahman
Software Architect & AI Engineer
Enterprise software architect with deep expertise in financial systems, distributed architecture, and AI-powered applications. Building large-scale systems at Fortune 500 companies. Specializing in LLM orchestration, multi-agent systems, and cloud-native solutions. I share battle-tested patterns from real enterprise projects.
Related Articles
The Visitor Design Pattern: Add Operations Without Modifying Classes
Master the Visitor Pattern in Java with practical examples. Add new operations to object structures without modifying existing classes using double dispatch.
JavaThe Template Method Pattern: The Recipe for Success
Master the Template Method Pattern in Java. Learn how to define the skeleton of an algorithm in a superclass but let subclasses override specific steps.
JavaThe Strategy Design Pattern: Kill the If-Else Statements
Master the Strategy Pattern in Java. Learn how to replace complex if-else logic with interchangeable algorithms and follow the Open/Closed Principle.
Comments
Comments are powered by GitHub Discussions.
Configure Giscus at giscus.app to enable comments.