Skip to article
ALGORITHMICSPatterns
Patterns5 min read

Flyweight

Sharing the heavy part between many objects — and the split that makes it possible.


A text editor with 50,000 characters on screen. If each character is an object holding its rendered glyph bitmap, that is 50,000 copies of the letter shapes — and there are only about 96 distinct letters in use.

The split

Divide every object’s data in two:

Store the intrinsic part once and pass the extrinsic part in at call time:

class Glyph { // intrinsic: one per distinct character
constructor(readonly char: string, readonly bitmap: Bitmap) {}
draw(x: number, y: number, colour: Colour) { // extrinsic: passed in
canvas.blit(this.bitmap, x, y, colour);
}
}
const GLYPHS = new Map<string, Glyph>();
function glyphFor(char: string): Glyph {
return GLYPHS.get(char) ?? GLYPHS.set(char, new Glyph(char, render(char))).get(char)!;
}

Move the sliders — note which one actually changes the total:

one object each
205.6 MB
shared glyphs
1.2 MB
ratio
172×

A glyph bitmap is ~4 kB and does not depend on where it appears; a position is 16 bytes and does. Storing the bitmap once per distinct character rather than once per occurrence is the entire pattern — and note that raising the distinct count barely moves the total, while raising the character count moves it a lot.

Flyweights must be immutable

If two thousand es share one Glyph, then mutating it changes all of them.

glyphFor('e').colour = 'red'; // every e on the page is now red

So intrinsic state has to be readonly, set at construction, and never reachable for modification. In practice this means the factory is the only thing that constructs them, and the class exposes no setters.

Where it already is

String interning. Java’s String.intern() and JavaScript’s Symbol.for() guarantee that equal strings share one object. Most language runtimes intern short strings and small integers automatically — Integer.valueOf(5) in Java returns a cached instance for anything from −128 to 127, which is why == works for small integers and stops working at 128.

Game engines. One mesh and one texture, thousands of trees. The per-tree data is a transform matrix.

Immutable value objects. A Money or a Colour that never changes can be shared safely by definition. Most flyweight usage in modern code is this, and nobody calls it a pattern — they just say “value type”.