Flyweight Pattern

Share the data that many small objects have in common, so a million objects cost little more than a handful.

Overview

The Flyweight pattern is one of the structural patterns in the Gang of Four book, Design Patterns (Gamma, Helm, Johnson and Vlissides, 1994). It answers one question: what do you do when a program needs a huge number of small objects, and most of them carry the same data? Instead of storing that data inside every object, you store it once in a shared object, the flyweight, and let every user point at it.

Interviewers use Flyweight to test whether you can tell shared state from per-object state, and whether you know the cost of sharing: the shared part must never change. A strong answer names the two kinds of state, shows the factory that hands out shared objects, and says where the pattern already lives in the platform you use.

The problem it solves

A text editor with a million characters, a game with a forest of ten thousand trees, a map with a million markers: each item is tiny, but the items add up. If each one stores its own copy of a font, a texture or an icon, memory is spent a million times on data that has only a few distinct values.

  • Every object stores all of its data — Each object stores only what makes it different
  • One million objects means one million copies of the font data — The few distinct fonts exist once each
  • Changing a shared value means touching every object — Changing it means replacing one flyweight
  • Simple to write — Needs a factory and a clear split of state

Two kinds of state

The pattern works by splitting an object's data into two parts. The intrinsic part is the same for many objects and does not depend on where the object is used. The extrinsic part is different for each object, or depends on its context. Intrinsic data goes into the shared flyweight. Extrinsic data stays with the object that uses the flyweight, or is passed in as a method argument.

  • Tree in a game — species name, color, texture — x and y position
  • Character in an editor — font, size, style — position in the text
  • Marker on a map — icon image, marker type — latitude and longitude
  • Must it be immutable? — Yes, because many objects see it — No

The split is the whole design decision. Put too much into the intrinsic part and there are too many distinct flyweights, so nothing is saved. Put too much into the extrinsic part and every call carries a long list of arguments.

Structure

  • Flyweight — Holds intrinsic state; its methods take extrinsic state as arguments — TreeType
  • Flyweight factory — Keeps a pool keyed by intrinsic state and returns the existing object when it can — TreeTypeFactory
  • Context — Holds extrinsic state plus a reference to a flyweight — Tree
  • Client — Asks the factory, never constructs flyweights directly — the loop that builds the forest

A runnable example

A forest of a thousand trees uses two tree types. The asserts show that only two TreeType objects exist and that the trees share them by reference.

Where you already use it

Language runtimes apply the same idea to values that programs create constantly.

  • Java Integer.valueOf(int) — boxed integers — Always caches values from -128 to 127 and may cache more
  • Java String.intern() — string contents — Returns one canonical String per distinct value from the string pool
  • CPython small integers — int objects — Keeps one object for each integer from -5 to 256
  • Python sys.intern() — string contents — Interned dictionary keys compare by pointer instead of by characters

The lesson from all four is the same: a shared object is safe only because it is immutable. A boxed Integer or a str never changes after it is created, so handing the same one to everybody cannot go wrong.

When not to use it

  • A few thousand objects or fewer — The saving is too small to pay for the extra indirection
  • Almost all state is per object — There is little to share, so you add a factory for nothing
  • The shared part must change per user — Sharing a mutable object means one change shows up everywhere
  • Objects must have their own identity — Two trees with the same type are still two trees; the pattern only shares the type, not the tree

What you will be able to do

  • Split an object's data into shared and per-object parts, and defend the split.
  • Write a factory that pools flyweights by a key and returns the same object for the same key.
  • Explain why a flyweight must be immutable, with a concrete bug that appears when it is not.
  • Point to the flyweights inside Java and Python and explain what they mean for == comparisons.
  • Say when the pattern is not worth it.

Interview questions

  • What is the difference between intrinsic and extrinsic state, and how do you decide which is which?
  • How does the flyweight factory work, and why must clients go through it?
  • Why must a flyweight be immutable? Show the bug.
  • Where does Flyweight appear in Java and Python, and why does it make == unreliable?
  • When does Flyweight make a design worse?

Sign up free to read the full topic

More Low-Level Design topics

Start free on Cariara · Coding problems · System design studio