Flyweight
Fit more objects in RAM by splitting out the state they all duplicate and sharing one immutable copy of it between them.
The problem
You built a game with a gloriously excessive particle system: bullets, missiles, shrapnel from explosions, all flying across the map. It runs beautifully on your machine. Your friend's older laptop crashes after a few minutes.
The debug logs blame RAM. Every particle is an object, and every object carries its own
color and sprite - fields far larger than the rest, and identical across every bullet
in the game. When the on-screen carnage peaks, the next allocation fails.
The solution
Sort the fields into two piles. Intrinsic state is constant and duplicated: the sprite, the color. Extrinsic state changes from object to object and over time: coordinates, movement vector, speed.
Then stop storing extrinsic state inside the object. Pass it into the methods that need it. What remains is a flyweight, and since all bullets share the same intrinsic state, three objects (bullet, missile, shrapnel) can now serve every particle in the game.
The extrinsic state has to live somewhere - normally in a small context object that holds the unique data plus a reference to its flyweight. Yes, you still have one context per particle, but they are now a few bytes each instead of a few kilobytes. Finally, a factory owns a pool of flyweights so identical intrinsic state never gets allocated twice, and immutability is mandatory: shared objects with setters are a horror story.
- 1Planting the first oak. The client asks the factory rather than constructing anything itself.
- 2Nothing matched in the pool, so one heavy object is built and cached. This happens once for oaks, ever.
- 3The context holds only the unique data plus a reference to the shared type. It is tiny.
- 4The ten-thousandth oak asks for the same intrinsic state.
- 5A pool hit. No allocation, no texture copy - the saving lands right here.
- 6Rendering walks the contexts, each of which knows its own coordinates and nothing else.
- 7The context passes its extrinsic state into the flyweight as arguments. That is the trick in one line.
Structure
Flyweight (shared, immutable, intrinsic state), Context (unique, extrinsic state plus a reference), Factory (the pool), Client (calculates or stores the extrinsic state). The behavior usually stays on the flyweight, taking extrinsic values as parameters; it can also move to the context, which then treats the flyweight as pure data.
Code
A forest of a million trees, backed by three TreeType objects.
When to use it
- Only when the program must hold a huge number of similar objects and that genuinely strains available RAM. All three conditions matter: many objects, real memory pressure, and duplicated state that can be extracted.
- Text editors (one glyph object per character code), map renderers, particle systems, tile-based games, and interned strings in your language runtime, which is Flyweight in the standard library.
Pitfalls
- Optimizing before measuring. This is the pattern most likely to be applied for sport. Profile first; if memory is not the bottleneck, you have added complexity for a rounding error.
- A mutable flyweight. One setter and every context sharing that instance changes at once. The resulting bug report will be a work of surrealist fiction.
- Trading RAM for CPU. Recomputing extrinsic state on every call can cost more than the memory you reclaimed.
- A pool that only grows. The factory keeps every flyweight alive forever by design. If intrinsic states are effectively unbounded, the cache becomes the leak.
- Bewildered newcomers. Splitting one intuitive class into flyweight plus context is never obvious from the outside. Leave a comment explaining why.
Don't confuse it with
- Singleton. A singleton restricts you to one instance and is often mutable. A flyweight class has as many instances as there are distinct intrinsic states, and all of them are immutable. A pool of size one is a coincidence, not a singleton.
- Facade. Perfect opposites in scale: Flyweight makes an enormous number of tiny objects viable, Facade makes one object stand in for an entire subsystem.
- Object pool. An object pool lends out mutable objects and expects them back; a flyweight pool hands out immutable ones that are shared simultaneously and never returned.
- Composite. Complementary rather than confusable. Shared leaf nodes in a large Composite tree are exactly the kind of thing you convert to flyweights when the tree outgrows memory.
Check yourself
Which of these belongs in the flyweight, and which is extrinsic state?