devnotes.

Command and Iterator Patterns

Command encapsulates a request or action as a standalone object, letting you parameterize code with actions, queue or log them, and support undo/redo — instead of directly calling a method, you wrap the intent to call it in an object.

interface Command {
    function execute()
    function undo()
}

class AddTextCommand implements Command {
    function __construct(private document, private text) {}
    function execute() { this.document.append(this.text) }
    function undo() { this.document.removeLast(this.text.length) }
}

class CommandHistory {
    private history = []

    function run(Command command) {
        command.execute()
        this.history.push(command) // remembered for potential undo later
    }

    function undoLast() {
        command = this.history.pop()
        command.undo()
    }
}

history = new CommandHistory()
history.run(new AddTextCommand(doc, "Hello"))
history.run(new AddTextCommand(doc, " World"))
history.undoLast() // removes " World", demonstrating undo functionality

Because each action is a full object rather than a bare function call, it can be stored, logged, queued for later execution, sent across a network, or reversed — this is exactly how undo/redo systems, task queues, and macro-recording features are typically implemented.

Iterator provides a standard way to sequentially access elements of a collection without exposing its underlying structure (array, linked list, tree, etc.) — the same idea covered concretely for PHP in the language-specific Generators chapter of the PHP notebook, but here as a general OOP concept applicable to any language.

interface Iterator {
    function hasNext(): bool
    function next()
}

class PlaylistIterator implements Iterator {
    private position = 0
    function __construct(private songs) {}

    function hasNext(): bool { return this.position < this.songs.length }
    function next() {
        song = this.songs[this.position]
        this.position += 1
        return song
    }
}

iterator = new PlaylistIterator(myPlaylist.songs)
while iterator.hasNext():
    print(iterator.next())

The caller loops through the playlist using only hasNext()/next(), with zero knowledge of whether songs are stored in an array, a linked list, or fetched lazily from a database — the iterator abstracts that detail away completely. Most modern languages provide this pattern as a built-in language feature (foreach in PHP/C#, for...of in JavaScript, Python's iterator protocol) rather than something you typically implement by hand, but understanding the underlying pattern explains what's happening when you use those built-in loop constructs.

Command and Iterator Design Patterns Explained | DevNotes