Skip to content
LLD Learn/Behavioral Patterns
Browsing as a guest. Sign in to save your progress and earn XP as you complete chapters.

Mediator & Iterator

6 min read

You'll learn to

  • -Use Mediator to centralize how a set of objects communicate instead of wiring them to each other directly
  • -Implement a custom Iterator that traverses a collection without exposing its internal structure

Mediator and Iterator round out the behavioral patterns most likely to appear in an LLD round. Mediator reduces chaotic many-to-many object communication to a hub-and-spoke shape; Iterator provides uniform traversal over a collection without exposing how that collection is actually stored internally.

Mediator: Replacing a Web of Direct References

Without Mediator, a chat room where every User object holds direct references to every other User to send messages becomes an N-to-N web of dependencies - adding a user means updating every existing user's reference list, and every User class is coupled to every other. Mediator introduces a central ChatRoom object: each User only knows about the ChatRoom, and the ChatRoom is responsible for routing a message from one user to the others.

A hub that routes communication instead of N-to-N references
class ChatRoomMediator:
    def __init__(self):
        self._users: list["User"] = []

    def register(self, user: "User") -> None:
        self._users.append(user)

    def send(self, sender: "User", message: str) -> None:
        for user in self._users:
            if user is not sender:
                user.receive(f"{sender.name}: {message}")

class User:
    def __init__(self, name: str, mediator: ChatRoomMediator):
        self.name = name
        self._mediator = mediator          # only knows the mediator, not other Users
        mediator.register(self)

    def send(self, message: str) -> None:
        self._mediator.send(self, message)

    def receive(self, message: str) -> None:
        print(f"{self.name} received: {message}")

Every User now depends on exactly one thing (ChatRoomMediator) instead of N-1 other Users, and adding a new user means one registration call, not updating every existing participant's reference list. The trade-off worth naming out loud: the Mediator itself can become a "god object" that knows too much if it grows unchecked, so its responsibility should stay scoped to routing/coordination, not business logic.

Iterator: Traversal Without Exposing Internals

Iterator provides a way to access the elements of a collection sequentially without exposing whether that collection is backed by an array, a linked list, or a tree. Most languages provide this for free via a built-in iterator protocol, but the pattern is worth understanding explicitly because custom collections in an interview (a custom tree structure, a paginated result set fetched from an API) often need their own iterator.

A custom iterator over a tree, hiding the traversal strategy
class TreeNode:
    def __init__(self, value, children=None):
        self.value = value
        self.children = children or []

class DepthFirstIterator:
    def __init__(self, root: TreeNode):
        self._stack = [root]

    def __iter__(self): return self

    def __next__(self):
        if not self._stack:
            raise StopIteration
        node = self._stack.pop()
        self._stack.extend(reversed(node.children))
        return node.value

for value in DepthFirstIterator(root):   # caller never sees the stack-based traversal logic
    print(value)

The value of a custom Iterator: the traversal strategy (depth-first here) is fully swappable - a BreadthFirstIterator with the same interface would let callers switch traversal order without changing a single line of calling code.

Interview Signal is part of Pro

See a real weak answer next to a real strong one for this exact topic.

Quiz is part of Pro

Test what you just read with a short quiz, and bank the XP.

ScaleDojo Logo
Initializing ScaleDojo