skip to content

What is the Flyweight design pattern, and what problem is it meant to solve?

level: juniorimportance: must knowfreq 55%

answer

  1. Many fine-grained objects, few distinct values
  2. Intrinsic = shared and immutable
  3. Extrinsic = passed in by the caller
  4. Factory interns: one instance per key
  5. Wins only when N ≫ K

basics

~20 s

Flyweight saves memory when a program needs a huge number of similar objects. Instead of one object per occurrence, identical parts are stored once and shared; the parts that differ per occurrence are passed in by the caller.

solid answer

~50 s

Flyweight is a structural pattern whose intent is to support very large numbers of fine-grained objects efficiently by sharing them. Each object's state is split in two: intrinsic state — the values that are identical across many occurrences and independent of where the object is used (a character's glyph shape, a tree species' mesh and texture, a chess piece's movement rules) — and extrinsic state, which depends on the usage context (position on the page, x/y coordinates, board square). Intrinsic state is stored in a shared, immutable flyweight object created and handed out by a factory that guarantees one instance per distinct value. Extrinsic state is kept by the client and passed as arguments to flyweight operations, so the shared object never holds it. The payoff is memory: N occurrences cost N small context records plus K distinct flyweights instead of N full objects. The cost is a less convenient API, an extra lookup, and a hard requirement that shared state be immutable.

go deeper

for a junior

Say it shares identical objects to save memory, and give one concrete example (characters in a document, trees in a scene).

for a middle

Name intrinsic vs extrinsic state explicitly, describe the factory that returns cached instances, and state the N ≫ K precondition.

for a senior

Add the cost model, the immutability and identity constraints, the factory-map lifetime/leak risk, and real-world instances such as string interning or dictionary-encoded columns.

for a principal

Frame Flyweight as one point on a spectrum of deduplication/representation choices (interning, dictionary encoding, structure-of-arrays, compression) and discuss when to push the concern below the API instead of into it.

## The problem Some designs are conceptually cleanest when every little thing is an object: every character in a document, every tree in a forest scene, every cell in a spreadsheet, every particle in a simulation. But if a document has 2,000,000 characters and each character object carries a font family, size, weight, colour, kerning table and glyph outline, you may need hundreds of bytes per character — hundreds of megabytes for a document whose text is 2 MB. The object model is right; the *representation* is wasteful, because those 2,000,000 objects only take on a few hundred genuinely distinct combinations of font attributes. **Flyweight** (from the *Design Patterns* / "Gang of Four" catalogue, structural category) is the pattern that keeps the fine-grained object model while removing the duplication. ## Core idea: split the state Flyweight partitions an object's fields into two groups. - **Intrinsic state** — values that are *context-free*: they are the same no matter where or how the object is used, and they are what makes two occurrences "the same thing". Examples: the glyph outline for the letter `a` in Times 12pt bold; the mesh and bark texture of an oak; the movement rules of a knight; the string `"US"` used as a country code. Intrinsic state lives inside the shared flyweight and must be **immutable**, because many unrelated clients see the same instance. - **Extrinsic state** — values that are *context-dependent*: they differ per occurrence and cannot be shared. Examples: the (x, y) position of that letter on the page; the coordinates, scale and rotation of that oak; the square the knight stands on; which row of a table holds `"US"`. Extrinsic state is stored by the client (often compactly, in parallel arrays or small structs) and **passed as parameters** into flyweight methods: `glyph.draw(canvas, x, y)` rather than `glyph.draw(canvas)`. ## Core mechanism: the factory Clients must not construct flyweights directly, or sharing breaks. A **flyweight factory** owns a map from *intrinsic key* → flyweight instance and returns an existing instance when the key repeats, creating one only on first request. This "one canonical instance per distinct value" behaviour is also called **interning**. The map is the only thing that grows with the number of *distinct* values, not with the number of *uses*. ## The arithmetic Let `N` be the number of occurrences, `K` the number of distinct intrinsic values, `S_i` the size of intrinsic state and `S_e` the size of extrinsic state. Without Flyweight you pay roughly `N × (S_i + S_e + object header)`. With Flyweight you pay `K × S_i + N × S_e + N × (a reference) + factory-map overhead`. Flyweight wins when `N ≫ K` and `S_i` is not tiny relative to `S_e`. If every occurrence is distinct (`K ≈ N`) you have added a hash map and gained nothing. ## Consequences - **Pro:** dramatic memory reduction; better cache locality (fewer distinct objects touched); shared immutable objects are trivially thread-safe to read; equality checks can often become reference checks. - **Con:** the API becomes parameter-heavy because extrinsic state must be threaded through call sites; there is a lookup cost on acquisition; the factory table itself consumes memory and, if unbounded and strongly referenced, can leak; and sharing forbids mutation, so any "customise this one instance" requirement forces you back out of the pattern. ## Where you have already seen it String interning, small-integer caches in many runtimes' boxing (e.g. `Integer.valueOf(-128..127)`), dictionary/​symbol encoding of repeated column values in analytical databases and Parquet/ORC files, enum constants, immutable colour/font registries in GUI toolkits, tile and sprite atlases in games, and the entity-component layouts where shared archetype data is separated from per-entity transforms. The pattern is far more common in library internals than in application code, which is exactly what you should say if asked whether you have "used" it.

  • Is Flyweight about speed or about memory?
    Primarily memory. Speed effects are indirect: fewer allocations and better cache locality can help, but the lookup in the factory and the extra parameter passing can also cost time. If your goal is latency, measure — do not assume Flyweight is faster.
  • Does Flyweight require immutability?
    The intrinsic state must be immutable in practice, because one instance is visible to many unrelated clients; mutating it would silently change every occurrence. Extrinsic state is owned by the client and may be mutable.

A print shop has one physical metal stamp per letter. To print a page it does not cast 2,000 stamps; it reuses ~40 stamps and records where on the page each is pressed. The stamp is intrinsic and shared; the press position is extrinsic and per-use.

saying these in an interview costs you the question

  • Describing Flyweight as a speed optimization first, ignoring that its stated intent is memory
  • Claiming Flyweight means 'only one instance exists' — that is Singleton; Flyweight is one instance per distinct value
  • Storing per-occurrence data such as coordinates inside the shared object
  • Letting clients call the flyweight constructor directly, which destroys sharing
  • Applying it when nearly every object is unique, so the cache costs more than it saves

context