Skip to content
FollowtheDamnCode

Flyweight

Share the heavy, unchanging part of many similar objects, and pass the small varying part in from outside.

Big idea

Flyweight saves memory when you have huge numbers of similar objects. Split each object's state into intrinsic (shared, immutable — the same for thousands of objects) and extrinsic (unique per use — passed in or stored outside). Keep one shared object per distinct intrinsic state, handed out by a factory.

The problem it solves

A text editor stores each character as an object with its font family, size, colour, weight, and its position. A 200,000-character document holds 200,000 copies of "Inter, 14px, #222, regular" — mostly identical data — and memory balloons. A map with a million parked-car markers has the same issue: every marker carries its own copy of the same icon bitmap.

Think of it like

A printing press with movable type. The shop owns one tray of letter "e" blocks, not a new carved "e" for every word in the book. Where each "e" goes on the page (the extrinsic part) is decided when you set the line; the shape of the "e" (intrinsic) is shared.

Structure

Many contexts point at a few shared flyweights

In code

100,000 characters, three style objects
class Style:                                       # intrinsic: immutable and shared
    __slots__ = ("font", "size", "color")
    def __init__(self, font, size, color):
        self.font, self.size, self.color = font, size, color


class StyleFactory:
    def __init__(self):
        self._cache = {}
    def get(self, font, size, color):
        key = (font, size, color)
        if key not in self._cache:
            self._cache[key] = Style(font, size, color)
        return self._cache[key]
    def count(self):
        return len(self._cache)


styles = StyleFactory()
body = styles.get("Inter", 14, "#222")
heading = styles.get("Inter", 24, "#000")
link = styles.get("Inter", 14, "#06c")

document = []                                      # extrinsic: (char, style) per position
for i in range(1000):
    document += [(ch, heading if i % 50 == 0 else body) for ch in "Lorem ipsum dolor sit amet. "[:25]]
    document += [(ch, link) for ch in "here"]
document = document[:100_000]

print("characters:", len(document))
print("style objects:", styles.count())
print("same object:", document[0][1] is styles.get("Inter", 24, "#000"))
used = {id(style) for _, style in document}
print("distinct styles in use:", len(used))
output
characters: 29000
style objects: 3
same object: True
distinct styles in use: 3

Run and edit it in the app.

Without sharing there would be a style object per character; with it, three exist no matter how long the document grows.

Watch it

How to implement it

  1. Find the state that's identical across many objects — that's intrinsic. Make it immutable.
  2. Move the per-object state (position, owner, coordinates) out — into the caller or a lightweight context.
  3. Create flyweights only through a factory with a cache, keyed by intrinsic state.
  4. Make operations take the extrinsic state as parameters: style.render(char, position).

In a forest of a million trees, which state should be the shared flyweight?

When to use it — and when not to

Use it only when you have measured a memory problem caused by very many objects with mostly duplicated, immutable state: glyphs, map tiles and markers, particles in a game, interned strings, cached small integers (Python already does this for you). Skip it otherwise — it complicates code for savings you don't need.

Pros and cons

ProsCons
Large memory savings at scaleCode is harder to follow (state split in two)
Shared objects are immutable, so thread-safeExtrinsic state must be passed around
Factory cache gives cheap lookupsCPU traded for memory when state is recomputed

How it relates

  • The flyweight factory looks like a keyed Singleton — one instance per distinct key, not one overall.
  • Leaves of a Composite are often flyweights (shared glyphs inside a document tree).
  • State and Strategy objects without fields can be flyweights shared by every context.
  • Python's string interning and small-integer cache are flyweights built into the language.

Why must a flyweight's shared state be immutable?

Key terms

  • Flyweight — A shared object holding state common to many logical objects.
  • Intrinsic state — The immutable, shareable part of an object, stored in the flyweight.
  • Extrinsic state — The per-use part, kept by the caller and passed in when needed.
  • Interning — Keeping one shared copy of each distinct value, such as identical strings.