Skip to content

// Design Patterns · 11

Flyweight

Millions of similar objectsleads toShare the common state

Share the common part of many small objects to save memory.

How it fits together

Flyweight structure«client»SheetRendererRender(sheet)StyleCacheGet(font, size, colour)one instance per keyCell A1row, col, value«record»CellStylefont, size, colourimmutable, sharedCell B2row, col, valueCell C9row, col, valueGet(key)once per keyper cellshared
uses / callscreates
  • SheetRenderer uses / calls StyleCache (Get(key))
  • StyleCache creates CellStyle (once per key)
  • SheetRenderer creates Cell A1 (per cell)
  • Cell A1 uses / calls CellStyle
  • Cell B2 uses / calls CellStyle (shared)
  • Cell C9 uses / calls CellStyle

Spot it

  • Millions of objects with mostly equal fields
  • The same strings or styles duplicated in memory
  • Out-of-memory when loading a large document

It costs

Saves memory for lookups and the rule that shared state never changes.

In code

public sealed record CellStyle(string Font, int Size, string Colour);​public readonly record struct Cell(int Row, int Column, string Value, CellStyle Style);​public sealed class StyleCache{    private readonly ConcurrentDictionary<CellStyle, CellStyle> _styles = new();​    public CellStyle Get(string font, int size, string colour)    {        var key = new CellStyle(font, size, colour);        return _styles.GetOrAdd(key, key);    }}​public sealed class SheetRenderer(StyleCache styles){    public Cell Place(int row, int column, string value, string font, int size, string colour) =>        new(row, column, value, styles.Get(font, size, colour));}
Go deeperThe full explanation and what to ask for · 1 min readExpand

Flyweight splits an object into intrinsic state, which many objects share and which never changes, and extrinsic state, which is unique per use and kept by the caller. A factory hands out one shared instance per distinct intrinsic value.

It only pays when there are very many objects and few distinct shared values, so measure before and after. Shared flyweights must be immutable: one caller changing a shared style changes it for every cell. An unbounded cache of flyweights becomes the leak it was meant to fix.

String interning and small-number caches in many runtimes are flyweights. The factory acts like a Singleton per key, and Composite trees with many identical leaves are the classic place to apply it.

Ask for it

  • flyweight
  • intrinsic state
  • extrinsic state
  • flyweight factory
  • interning
  • immutability

Rendering a 2-million-cell sheet allocates a CellStyle per cell. Make CellStyle immutable, add a StyleCache that returns one shared instance per (font, size, colour), and keep only row, column, value and a style reference per cell. Measure memory before and after.