You wrote a for (item : collection) loop this morning and didn’t think about it once. That reflex is the payoff of a design decision made for you decades ago.
Picture the alternative. Your service holds recent user events in a ring buffer — a fixed-size array that overwrites its oldest entry when it fills, so the newest event might physically sit at index 2 while the oldest sits at index 5. Now a teammate needs to “just loop over the events.” To do it, they have to know there’s a head pointer, that logical order isn’t array order, and that reading the buffer means modular arithmetic against its capacity. Swap the ring buffer for a linked list next quarter and every one of those loops breaks — because each one reached into the structure’s guts.
The problem isn’t the ring buffer. It’s that how the collection stores its elements and how you walk them got welded together, so the caller can’t stay ignorant of the layout. The Gang of Four named the fix — and it’s the most-used pattern in the world.
The intuition: the channel-up button
Point a remote at your TV and press channel-up. You don’t know — or care — whether the tuner is scanning frequencies, stepping through a cable lineup, or hopping an IPTV playlist. The button gives you one verb: advance to the next thing. The tuner’s internals could be swapped entirely and your thumb would never notice.
That button is an iterator. The TV is the aggregate — the collection that knows how it’s really wired. The remote gives you a uniform way to move through the channels without ever exposing the wiring. hasNext() is “is there a channel after this one,” next() is the press.
The structure
Two roles, one factory method between them. The Aggregate exposes a createIterator() (in Java, iterator()); the Iterator it hands back carries the cursor and answers hasNext()/next(). The client talks only to the iterator interface.
The load-bearing arrow is RingBuffer → creates → RingCursor. The collection is the only thing that knows its own layout, so it’s the only thing qualified to build a cursor that walks it correctly. The client, on the far left, is wired to the two interfaces and never learns the word “RingBuffer.”
From here the members-only walkthrough builds the real thing: the two interfaces and a live ring-buffer implementation whose wrap-around hides entirely inside the cursor, the for-each-is-just-sugar desugaring, the external-vs-internal and eager-vs-lazy split (with a generator that streams a 42,000-request paginated API one page at a time), the fail-fast ConcurrentModificationException trap and its fix, a BST-iterator interview challenge, and a quiz to check yourself.
Keep reading with Premium
You've reached the members-only part of this deep-dive — the full implementation, the interactive ring simulator, and the step-by-step walkthrough. Unlock it with a membership.
Discussion
Loading the conversation…
Discussion
Loading the conversation…