skipnothing/Design Patterns

Proxy

A photo grid builds a full-resolution HighResImage for all two hundred files the moment the folder opens, decoding megabytes the user scrolls past. The screen shows nine at a time; the rest loaded for nothing.

  • ▸A stand-in with the same interface drops into existing call sites; not one caller changes.
  • ▸Swap only the gate inside it and the same shape becomes lazy load, auth, cache, or remote.
  • ▸The transparency that makes it painless also hides cost: a read can hit the network or throw.
BUILDS ON
01

The eager load

A photo grid opens a folder and builds a HighResImage for every file in it:

class HighResImage {
  constructor(path) {
    this.pixels = decodeFromDisk(path); // reads + decodes ~4MB
  }
  display() { paint(this.pixels); }
}
const grid = paths.map(p => new HighResImage(p));

Two hundred files, two hundred decodes, all before the first frame paints. The screen shows nine thumbnails at a time. The user glances at the folder and closes it. The other hundred-ninety-one images decoded megabytes that nobody ever looked at.

The cost is in the constructor, and the constructor runs whether or not anyone calls display(). Same shape shows up everywhere expensive work hides behind new: a report page that runs a slow aggregation query the instant it's constructed, a config object that opens a network connection in its initializer. The work is tied to *creation*, but you only need it on *use*, and the two have drifted apart.

Moving the decode out of the constructor and into display() is the obvious fix, except now every call site that builds an image has to remember to handle a not-yet-loaded state, and the loading check leaks into all two hundred of them. You want the deferral without touching the callers.

WORK TIED TO CREATION, NOT USE

Keep going, sign up to unlock the rest

4 more parts in this topic, plus 18+ more topics in Design Patterns.

Sign up, it's freeSee the full Design Patterns
Structural Patterns0/5#9 Adapter
#11 Facade