design·lab

Structural pattern

Flyweight

When you need thousands of similar objects, stop letting every instance carry its own copy of the same heavy data — share it instead.

✗ The problem

A forest of 1,000,000 heavy trees

Each Tree stores its own mesh, texture and color — even though most trees share the same handful of species.

class Tree {
  constructor(x, y, name, color) {
    this.x = x; this.y = y;
    this.name  = name;
    this.color = color;
    // duplicated on EVERY instance:
    this.mesh    = loadMesh(name);     // ~1.5MB
    this.texture = loadTexture(name);  // ~1.5MB
  }
}
// 1,000,000 × its own mesh+texture → 💥
Tree #1
+mesh +texture
Tree #2
+mesh +texture
Tree #3
+mesh +texture
Tree #…
+mesh +texture
Duplicated intrinsic data (mesh, texture, color) repeats per instance — memory scales with tree count, not with the number of unique species.
✓ The pattern

Split intrinsic (shared) from extrinsic (per-instance)

A TreeType flyweight holds the heavy, shared state. A factory hands out one instance per unique species. Each Tree keeps only its own x/y + a reference.

class TreeType {          // shared
  constructor(name, color) {
    this.name = name; this.color = color;
    this.mesh = loadMesh(name);  // heavy, once
  }
}

class TreeFactory {
  static cache = new Map();
  static get(name, color) {
    const key = name + color;
    if (!this.cache.has(key))
      this.cache.set(key, new TreeType(name, color));
    return this.cache.get(key);   // reuse!
  }
}

class Tree {                // per-instance
  constructor(x, y, type) {
    this.x = x; this.y = y; this.type = type;
  }
}
Tree
12,45
Tree
88,3
Tree
50,50
Tree …
x,y
↓ all reference →
TreeType
Oak 🌳
TreeType
Pine 🌲
TreeType
Birch 🌴
✓ See it live

Plant 1,000 trees — count the flyweights

Only 3 species exist, so the factory ever creates 3 TreeType flyweights, no matter how many Tree instances reference them.

Tree instances 0
Unique TreeType flyweights 0
✓ Takeaway

Share state, slash memory

  • Intrinsic state (shared, immutable) lives in the flyweight; extrinsic state (unique, contextual) is passed in by the caller.
  • A factory guarantees one flyweight per unique key — new callers reuse, they never duplicate.
  • You already see it: font glyphs, game sprites/particles, table-cell styles.
  • Caution: it adds a layer of indirection — reach for it only when object count or memory pressure genuinely hurts (YAGNI otherwise).
🎯 Principle applied: Flyweight is DRY for memory — one shared copy of common state — with a clean SRP split between shared (intrinsic) and per-object (extrinsic) data.