2.7 Flyweight
The Flyweight pattern exists purely for memory. When you need a huge number of fine-grained objects (hundreds of thousands of trees, every character on a page, every icon on a map), building each one fully will blow up memory. Flyweight splits an object's state in two:
- Intrinsic state: shareable, context-independent parts — a tree's species, its texture, a character's glyph.
- Extrinsic state: per-object, non-shareable parts — coordinates, a color instance.
Intrinsic state is extracted and shared as a single copy across all objects; extrinsic state is passed in by the client at call time.
In the forest lab below, you plant hundreds or thousands of trees, yet the counter shows that only a handful of "flyweight objects" were actually created.
A factory handles reuse
class TreeFactory {
private static Map<String, TreeType> pool = new HashMap<>();
static TreeType get(String name) {
return pool.computeIfAbsent(name, TreeType::new); // reuse if present
}
}
// extrinsic state passed in at use time, not stored in the flyweight
treeType.draw(canvas, x, y);Key point: the coordinates x, y must never be stored inside TreeType, or sharing breaks. The comparator below uses a slider for object count to quantify the memory gap "with vs without flyweight."
Cost and boundaries
Flyweight is not free:
- You must cleanly partition intrinsic / extrinsic state, which makes the code more roundabout.
- Flyweight objects usually must be immutable (since they're shared, no single user may quietly mutate one).
- If the object count is small to begin with, flyweight only adds complexity.
In one line: Flyweight trades CPU/complexity for memory, worthwhile only when memory truly is the bottleneck and objects are highly repetitive. Java's Integer.valueOf() cache (-128 to 127) is a built-in flyweight.