Iterator Pattern: Visit Every Element, One Seat at a Time
Learn the Iterator pattern with a railway ticket checker story. Build a custom iterator in TypeScript, use for...of and generators, plus C# IEnumerable.
๐ Mr. Verma walks down coach S4
The 12301 Express rolls out of Howrah station towards Delhi. A few minutes after departure, Mr. Verma โ the TTE (Travelling Ticket Examiner), in his black coat with a chart tucked under his arm โ slides open the door of coach S4 to check tickets.
How does he do it? Does he need to know how the railway's reservation computer stores passenger data โ in which database, in which format? Not at all. He simply starts at seat 1 and moves forward: seat 1, seat 2, seat 3... At each seat he asks, "Ticket please," checks it, and moves to the next seat. When he reaches the last seat of the coach, he knows he is done, and he moves to the next coach.
Tonight, coach S4 carries four passengers we will keep meeting: Riya (seat 1, ticket in hand), Arjun (seat 2, ticket folded in his book), Meera (seat 3, who โ oh no โ boarded without a ticket), and Kabir (seat 4, fast asleep but ticketed).
Look at what Mr. Verma really needs to do his job:
- A way to get the next passenger.
- A way to know whether any passengers remain.
- His own memory of where he currently is (seat 3, coach S4).
That is all. He does not care whether the coach has side berths or cabins, whether passengers boarded in order, or how the seating chart was prepared. The coach can keep its arrangement private; Mr. Verma just walks it one seat at a time.
And here is a lovely detail: while Mr. Verma checks tickets from seat 1 forward, Santosh from the pantry car enters from the other end, taking dinner orders from the last seat backwards. Two people, walking the same coach, each remembering their own position, never disturbing each other.
Mr. Verma is an iterator. The coach is a collection. This whole lesson is about giving your code its own ticket examiner.
Here is his routine as a flow โ notice it is just two questions, asked again and again:
And here is the same walk told as a journey through the evening:
๐ฏ What is the Iterator pattern?
Iterator (also known as Cursor) is a behavioral design pattern from the Gang of Four (GoF) book (1994).
A definition for your notes:
The Iterator pattern lets you traverse the elements of a collection one at a time, without exposing how the collection stores them inside. The traversal logic โ current position, what comes next, are we done โ moves out of the collection into a separate iterator object.
The pattern has four parts. Match them with the train:
| Pattern part | What it does | Railway version |
|---|---|---|
| Iterator interface | Declares hasNext() and next() | The job description of "someone who walks seats" |
| Concrete iterator | Tracks position, knows what comes next | Mr. Verma with his memory of seat 3 |
| Collection interface | Declares createIterator() | The coach door saying "start from seat 1" |
| Concrete collection | Stores the data, storage only | Coach S4 and its seating chart |
- Iterator interface โ usually two methods:
hasNext()("are there more?") andnext()("give me the current one and move ahead"). - Concrete iterator โ implements those methods for one collection and one traversal order. It holds the current position. Our Mr. Verma.
- Collection interface โ declares a factory method,
createIterator(), that hands out a fresh iterator. The coach saying "here, start from seat 1." - Concrete collection โ the actual data structure, which stays focused on storage only.
Because every iterator looks the same from outside, the client's loop never changes โ whether the data lives in an array, a tree, a hash set, or arrives lazily from a file.
Memory trick: an iterator answers just two questions, again and again โ "Anyone left?" and "Who is next?" If you can build an object that answers those two questions for your data, you have built an iterator. Everything else is detail.
This pattern has a special place among the GoF patterns: it is so useful that almost every modern language absorbed it into its syntax. JavaScript's for...of, Python's for...in, C#'s foreach, Java's enhanced for โ all of them are the Iterator pattern wearing the language's own clothes. We will use both the hand-made version and the built-in version below.
The whole lesson, as one mind map for your notebook:
๐ The problem it solves
Why can't clients just reach into the collection directly? Let us see.
Suppose the railway stores coach S4's passengers in a plain array. A naive ticket-checking program might do this:
// โ The client reaches inside the collection's private structure
for (let i = 0; i < coach.passengerArray.length; i++) {
checkTicket(coach.passengerArray[i]);
}Two big problems hide here.
Problem 1: The internal structure leaks. The client now knows the coach uses an array called passengerArray. The pantry program knows it. The cleaning-schedule program knows it. Tomorrow the railway changes storage to a Map keyed by seat number โ and every one of those loops breaks. Private layout has become public knowledge, and changing it means hunting down every loop in the codebase. It is as if Mr. Verma, Santosh, and the coach attendant all had to memorize the reservation database schema just to walk down the aisle.
Problem 2: "Next" is not always obvious. An array has an easy "next": index plus one. But what if the data is a tree? Say the railway groups coaches โ compartments โ berths in a tree structure. What is "the next passenger" now? Depth-first? Breadth-first? Left to right? Every client would need to learn tree-walking, write the same stack-based traversal code, and probably write it slightly wrong. The walking logic gets duplicated at every call site, with nowhere proper to live.
And a third, quieter problem: if the traversal code lives inside the collection (a walkDepthFirst() method here, a walkBreadthFirst() method there), the collection class swells into a grab-bag of algorithms โ and since "current position" has only one home, two simultaneous traversals become impossible. Mr. Verma and Santosh would have to share one bookmark, fighting over whose seat number it remembers.
The Iterator pattern fixes all three at once: traversal moves into its own small object, the collection's insides stay hidden, each traversal order is one tested class, and every iterator carries its own position so many can run in parallel.
โ๏ธ How it works, step by step
Let us build the railway coach properly.
Step 1: Declare the Iterator interface โ hasNext(): boolean and next(): Passenger.
Step 2: Declare the collection interface โ one factory method, createIterator(): Iterator. Note that createIterator() is literally the Factory Method pattern producing iterators.
Step 3: Implement the concrete collection. The coach stores passengers however it wants โ here, an array of seats. Storage code only.
Step 4: Implement the concrete iterator. It keeps a reference to the coach and a position field. All the "which seat comes next" logic lives here, sealed away from clients.
Step 5: The client loops through the interface. while (it.hasNext()) check(it.next()). The same loop works for any collection that hands out iterators.
Step 6 (the modern step): plug into the language's iteration protocol. Implement Symbol.iterator in JavaScript/TypeScript, IEnumerable<T> in C#, __iter__ in Python โ and clients can use the native for...of / foreach / for...in loop instead of calling hasNext()/next() by hand.
Watch the conversation at runtime. The coach is asked exactly once โ for an iterator. After that, the client talks only to the iterator:
Need a second traversal order โ say, Santosh walking from the back? Add a ReverseIterator class and a second factory method. The coach's storage code is not touched, and the client's loop does not change either. That is the Open/Closed Principle at work.
An iterator also lives a small, strict life. It is born fresh, it walks, and one day it is exhausted โ and an exhausted iterator never walks again:
Keep Figure 5 in mind for the generator section below โ "exhausted iterators stay exhausted" is the source of a very common beginner bug.
๐ป Real-life code example
Here is the full railway coach in TypeScript. It shows both styles: a hand-made classic iterator, and the modern Symbol.iterator / generator style that powers for...of.
// The element we iterate over
interface Passenger {
seatNo: number;
name: string;
hasTicket: boolean;
}
// ----- Step 1: the Iterator interface -----
interface PassengerIterator {
hasNext(): boolean;
next(): Passenger;
}
// ----- Step 2: the collection interface -----
interface IterableCoach {
createIterator(): PassengerIterator;
}
// ----- Step 3: the concrete collection (storage only) -----
class Coach implements IterableCoach {
// Private! No client ever touches this directly.
private seats: Passenger[] = [];
board(name: string, hasTicket: boolean): void {
this.seats.push({ seatNo: this.seats.length + 1, name, hasTicket });
}
get seatCount(): number {
return this.seats.length;
}
passengerAt(index: number): Passenger {
return this.seats[index];
}
// Factory methods โ one per traversal order
createIterator(): PassengerIterator {
return new TTEIterator(this); // front to back
}
createReverseIterator(): PassengerIterator {
return new PantryIterator(this); // back to front
}
}
// ----- Step 4: concrete iterators (walking only) -----
class TTEIterator implements PassengerIterator {
private position = 0; // Mr. Verma's own memory of where he stands
constructor(private coach: Coach) {}
hasNext(): boolean {
return this.position < this.coach.seatCount;
}
next(): Passenger {
return this.coach.passengerAt(this.position++);
}
}
class PantryIterator implements PassengerIterator {
private position: number;
constructor(private coach: Coach) {
this.position = coach.seatCount - 1; // Santosh starts from the last seat
}
hasNext(): boolean {
return this.position >= 0;
}
next(): Passenger {
return this.coach.passengerAt(this.position--);
}
}
// ----- Step 5: the client drives the loop -----
const coachS4 = new Coach();
coachS4.board("Riya", true);
coachS4.board("Arjun", true);
coachS4.board("Meera", false); // oh no!
coachS4.board("Kabir", true);
console.log("--- Mr. Verma checking tickets (front to back) ---");
const tte = coachS4.createIterator();
while (tte.hasNext()) {
const p = tte.next();
console.log(
`Seat ${p.seatNo}: ${p.name} โ ${p.hasTicket ? "ticket OK" : "NO TICKET, fine!"}`,
);
}
console.log("--- Santosh taking orders (back to front) ---");
const pantry = coachS4.createReverseIterator();
while (pantry.hasNext()) {
console.log(`Seat ${pantry.next().seatNo}: dinner order taken`);
}Output:
--- Mr. Verma checking tickets (front to back) ---
Seat 1: Riya โ ticket OK
Seat 2: Arjun โ ticket OK
Seat 3: Meera โ NO TICKET, fine!
Seat 4: Kabir โ ticket OK
--- Santosh taking orders (back to front) ---
Seat 4: dinner order taken
Seat 3: dinner order taken
Seat 2: dinner order taken
Seat 1: dinner order takenBoth iterators walked the same coach in the same program without touching each other, because each one carries its own position. The client never saw the seats array. Mr. Verma and Santosh, each with their own bookmark.
Here is the class structure you just built:
By the way, here is what Mr. Verma found tonight across the whole train โ iteration produces data, and data loves a chart:
โจ The built-in way: Symbol.iterator and generators
Modern languages bake this pattern into their syntax. In JavaScript and TypeScript, any object with a [Symbol.iterator]() method that returns an object shaped like next(): { value, done } is iterable, and for...of will happily walk it. A generator function (function* with yield) is a shortcut that builds the iterator object for you โ no position bookkeeping, no class:
class ModernCoach {
private seats: Passenger[] = [];
board(name: string, hasTicket: boolean): void {
this.seats.push({ seatNo: this.seats.length + 1, name, hasTicket });
}
// A generator: the language writes the iterator for us.
// Execution PAUSES at each yield and resumes on the next loop turn.
*[Symbol.iterator](): Generator<Passenger> {
for (const p of this.seats) {
yield p;
}
}
// A second, filtered traversal โ lazily yields only defaulters
*ticketlessPassengers(): Generator<Passenger> {
for (const p of this.seats) {
if (!p.hasTicket) yield p;
}
}
}
const coach = new ModernCoach();
coach.board("Riya", true);
coach.board("Meera", false);
coach.board("Kabir", true);
// The famous for...of โ this IS the Iterator pattern, built in
for (const p of coach) {
console.log(`${p.name} is in the coach`);
}
for (const p of coach.ticketlessPassengers()) {
console.log(`${p.name}, please pay the fine.`); // Meera, please pay the fine.
}Compare ticketlessPassengers() with the 15-line PantryIterator class above โ the generator does the same job in four lines. Generators are also lazy: values are produced one at a time, only when asked. That means you can even iterate things that never end:
// An infinite iterator โ only possible because values come lazily
function* seatNumbers(): Generator<number> {
let n = 1;
while (true) yield n++; // pauses here after each value
}
const seats = seatNumbers();
console.log(seats.next().value, seats.next().value, seats.next().value); // 1 2 3
// No infinite loop โ we only pulled three values.Use the classic hand-made iterator when you need full control (resettable cursors, custom invalidation rules) or when teaching. Use generators and for...of in everyday code โ they are the pattern, idiomatically.
College corner: generators are your first taste of lazy evaluation โ computing a value only at the moment somebody actually asks for it. The eager approach builds the whole list first, then hands it over; the lazy approach hands over one item at a time and pauses. This changes what is possible: you can stream a 10 GB log file line by line in constant memory, model an infinite sequence (all seat numbers, all primes), and chain lazy stages into pipelines where nothing runs until the final consumer pulls. Haskell makes laziness the default for the whole language; Python's generators, JavaScript's function*, and C#'s yield return give you the same superpower on demand. The mental model to keep: a generator is a paused function that remembers where it stopped โ Mr. Verma frozen mid-aisle, one foot in the air, until someone calls next().
The memory difference is dramatic and easy to chart. Suppose a program must process one lakh booking records:
The lazy bar is not a typo. A generator holds one record at a time โ the current one โ no matter how long the train is.
๐ฆ The same idea in C#
C# expresses the pattern through IEnumerable<T> / IEnumerator<T>, and the yield return keyword plays the role of generators. Every foreach loop you have ever written was the Iterator pattern in disguise:
public record Passenger(int SeatNo, string Name, bool HasTicket);
public class Coach : IEnumerable<Passenger>
{
private readonly List<Passenger> _seats = new();
public void Board(string name, bool hasTicket)
=> _seats.Add(new Passenger(_seats.Count + 1, name, hasTicket));
// yield return = C#'s generator. The compiler builds the
// iterator class (position tracking and all) behind the scenes.
public IEnumerator<Passenger> GetEnumerator()
{
foreach (var p in _seats)
yield return p; // pause here, resume on next iteration
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
// A second traversal: only the ticketless, lazily
public IEnumerable<Passenger> Ticketless()
{
foreach (var p in _seats)
if (!p.HasTicket)
yield return p;
}
}
// Client
var coach = new Coach();
coach.Board("Riya", true);
coach.Board("Meera", false);
coach.Board("Kabir", true);
foreach (var p in coach) // foreach drives the iterator
Console.WriteLine($"Seat {p.SeatNo}: {p.Name}");
foreach (var p in coach.Ticketless())
Console.WriteLine($"{p.Name}, please pay the fine.");
// LINQ is a pipeline of iterators chained together:
var names = coach.Where(p => p.HasTicket).Select(p => p.Name).ToList();When the yield return line runs, the method pauses, hands one item to the caller, and resumes from the same spot on the next loop turn. Nothing is stored in memory up front โ items are generated on demand. The whole of LINQ (Where, Select, Take...) is iterator objects chained into lazy pipelines.
Python tells the same story with __iter__/__next__, generator functions, and the for ... in loop:
class Coach:
def __init__(self):
self._seats = []
def board(self, name, has_ticket):
self._seats.append((len(self._seats) + 1, name, has_ticket))
def __iter__(self):
# A generator method: Python builds the iterator for us
for seat in self._seats:
yield seat
def ticketless(self):
for seat_no, name, has_ticket in self._seats:
if not has_ticket:
yield (seat_no, name)
coach = Coach()
coach.board("Riya", True)
coach.board("Meera", False)
for seat_no, name, has_ticket in coach: # for...in drives __iter__
print(f"Seat {seat_no}: {name}")
for seat_no, name in coach.ticketless():
print(f"{name}, please pay the fine.") # Meera, please pay the fine.College corner: LINQ and Python's itertools show why lazy iterator pipelines matter. In coach.Where(...).Select(...).Take(3), no work happens when the pipeline is built โ each stage is just an iterator wrapping another iterator. Only when something pulls (a foreach, a ToList()) does data flow, and it flows one item at a time through all stages, stopping completely after the third match thanks to Take(3). This is called deferred execution, and it has a classic trap: because the query re-runs every time you enumerate it, iterating the same LINQ query twice does the work twice โ and if the underlying data changed in between, you get different answers. Materialize with ToList() when you need a stable snapshot.
๐ Where you see it in real software
Iterator may be the most-used design pattern on Earth โ most of the time invisibly.
1. Every for...of, foreach, and for...in loop. JavaScript arrays, strings, Maps, and Sets all implement Symbol.iterator. The spread operator [...thing] and destructuring also drive iterators underneath.
2. Python generators and itertools. Python's for loop calls iter() and next() under the hood. Generators (yield) produce values lazily, so you can stream a 10 GB log file line by line using almost no memory. The itertools module is a toolbox of composable iterators.
3. C# IEnumerable and LINQ. yield return methods do not build a collection in memory โ they describe how to produce items when asked. LINQ chains these lazy sequences into query pipelines.
4. Java Collections. java.util.Iterator and Iterable power the enhanced for-loop across ArrayList, HashSet, TreeMap, and friends. Java's iterators are famously fail-fast: modify the collection mid-walk and you get a ConcurrentModificationException instead of silent corruption.
5. Databases and APIs. A database cursor (remember, "Cursor" is this pattern's alternate name) walks query results row by row without loading the whole result set. Paginated APIs ("give me the next 20 results") are iterators over the network โ the "next page" token is the iterator's saved position.
6. File systems and streams. Reading a file line by line, walking a directory tree, consuming a message queue โ all are iterator-shaped: anyone left? who is next?
| Real software | The collection | The iterator |
|---|---|---|
JavaScript for...of | Array, Map, Set, string | The object from [Symbol.iterator]() |
Python for loop | Any object with __iter__ | Generator / iterator object |
C# foreach + LINQ | Anything IEnumerable<T> | IEnumerator<T> (often compiler-made via yield) |
| Java collections | ArrayList, HashSet... | java.util.Iterator (fail-fast) |
| Databases | Query result set | Cursor |
| Web APIs | Server-side data | Pagination tokens ("next page") |
| Message queues | Stream of messages | The consumer's offset |
๐ค When to use it and when not to
| Situation | Use it? | Why |
|---|---|---|
| The collection's inside structure is complex (tree, graph, paged data) and should stay hidden | โ | Clients walk it without learning the layout |
| The same data needs several traversal orders (forward, reverse, filtered) | โ | One iterator class per order; storage untouched |
| Traversal code is copy-pasted at many call sites | โ | Centralize the walk in one tested iterator |
| You want one loop that works across different collection types | โ | Code against the iterator interface |
| Data is huge or infinite and must be produced lazily | โ | Generators / yield stream items on demand |
| You are writing a custom data structure others will loop over | โ | Implement the language's iteration protocol |
| It is a small plain array used in one place | โ | The language's built-in loop already does it |
| You need random jumps (give me element #57 directly) | โ | Iterators are sequential; use indexing |
| You will heavily modify the collection while walking it | โ ๏ธ | Iterator invalidation โ collect first or use fail-safe designs |
Place your own situation on this map. The more hidden your structure and the more ways you need to walk it, the stronger the case for a proper iterator:
โ ๏ธ Common mistakes students make
Mistake 1: Modifying the collection while iterating it. If Mr. Verma removes a ticketless passenger from the array while walking it, every seat after that shifts, and the iterator's saved position points at the wrong person โ some passengers get skipped. In Java this throws ConcurrentModificationException; in JavaScript it silently skips elements. Fix: collect what to remove first, then remove after the loop ends.
Mistake 2: Forgetting that one iterator is one-way and single-use. A generator that has finished is exhausted โ looping over it a second time yields nothing, and beginners stare at the empty second loop in confusion. Remember Figure 5: Exhausted has no arrow back to Walking. If you need to traverse again, ask the collection for a fresh iterator (createIterator() again, or call the generator function again).
More traps:
- Calling
next()without checkinghasNext(). Walking past the last seat returnsundefined(or throws). Always pair the two questions โ or just usefor...of, which pairs them for you. - Putting traversal logic back into the collection. If your
Coachclass growswalkForward(),walkBackward(),walkTicketless()methods that all manage positions, you have undone the pattern. Positions belong in iterator objects. - Sharing one iterator between two loops. Each traversal needs its own iterator, otherwise the two loops fight over a single position โ like Mr. Verma and Santosh sharing one bookmark.
- Assuming iteration order where none is promised. Hash-based sets may not promise an order. Depend only on what the collection documents.
- Enumerating a lazy pipeline twice by accident. Each enumeration re-runs the work (see the College corner on deferred execution). Snapshot with
ToList()/list(...)/[...spread]when you need the same answer twice.
๐ช Compare with cousins
| Pattern | Main question | How it relates to Iterator |
|---|---|---|
| Iterator | "How do I visit every element, one by one?" | โ |
| Composite | "How do I treat a tree of objects as one object?" | Iterator is the clean way to walk a Composite tree without exposing nodes |
| Factory Method | "Who decides which concrete object to create?" | createIterator() is a factory method returning the right iterator |
| Visitor | "How do I run an operation on every element?" | Iterator decides how to move; Visitor decides what to do at each stop |
| Memento | "How do I save and restore state?" | Can snapshot a traversal's position so a long walk can resume later |
| Command | "How do I package a request as an object?" | Different goal โ but a queue of commands is usually iterated by a worker |
The pair to remember is Iterator + Visitor: the iterator is Mr. Verma's walking route through the train; the visitor is what he does at each seat (check ticket? take dinner order? count children?). Separating "how to traverse" from "what to do" lets you mix and match both freely โ the same forward walk serves ticket checking in the morning and blanket distribution at night.
๐ฆ Quick revision box
+=====================================================================+
| ITERATOR PATTERN โ QUICK REVISION |
+=====================================================================+
| WHAT : Walk a collection element by element WITHOUT exposing |
| how it stores things inside. |
| STORY : Mr. Verma the TTE checks tickets seat by seat. He needs |
| only "anyone left?" and "who is next?" plus his own |
| position. Santosh walks the same coach the other way. |
| ROLES : Iterator (hasNext/next) | ConcreteIterator (position) |
| Collection (createIterator factory) | Client (the loop) |
| MODERN : for...of + Symbol.iterator (JS/TS), function* + yield, |
| IEnumerable + yield return (C#), __iter__ (Python) |
| LAZY : generators produce values on demand -> huge or infinite |
| sequences cost almost no memory |
| WINS : hidden internals, many traversal orders, parallel and |
| pausable walks, one loop for every collection |
| RISKS : modifying while iterating, exhausted single-use |
| iterators, overkill for tiny arrays |
| SEEN IN : every for-of / foreach loop, LINQ, Python itertools, |
| database cursors, paginated APIs |
+=====================================================================+๐๏ธ Practice exercise
Type these yourself. Fingers teach the brain.
Task 1: Attendance roll-call. Build a ClassRoom collection storing students as records with roll number, name, and an isPresent flag. Write a classic hand-made RollCallIterator (with hasNext()/next()) that visits students in roll-number order, even if they were added in random order. The client loop should print "Roll 1: Riya โ Present", and the client must never touch the internal array.
Task 2: Two traversals, one collection. Add a generator method *absentees() to your ClassRoom that lazily yields only absent students, and implement [Symbol.iterator] so plain for (const s of classRoom) works for all students. Run both loops in the same program over the same object to prove two iterators do not disturb each other โ your own Mr. Verma and Santosh.
Task 3 (challenge): Book of pages. Model a Book whose chapters each contain pages (a small tree: book โ chapters โ pages). Write a PageIterator that walks every page of the whole book in reading order, hiding the chapter structure completely โ the client just does for (const page of book). Hint: keep chapterIndex and pageIndex inside the iterator, or let a generator with two nested loops do the bookkeeping for you. Bonus: make an infinite revisionQuestions() generator that cycles through the book's questions forever, and pull just the first ten with a loop that breaks.
Finish Task 3 and you have done what for...of does for you every day โ and you will understand why the GoF called the iterator a humble "cursor" that quietly runs the whole programming world, one seat at a time. ๐
Frequently asked questions
- What is the Iterator pattern in simple words?
- It lets you walk through the elements of a collection one by one without knowing how the collection stores them inside. The walking logic lives in a separate iterator object that remembers the current position.
- Why not just use a normal for loop with an index?
- An index loop only works when the data sits in an array. Trees, sets, linked lists, and data coming from a network have no simple index. An iterator gives you one uniform way to walk any of them.
- Is for...of in JavaScript the Iterator pattern?
- Yes. for...of works on any object that implements Symbol.iterator and returns an object with a next() method. Arrays, strings, Maps, and Sets all ship with built-in iterators, which is why for...of works on all of them.
- What is the difference between an iterator and a generator?
- A generator is a shortcut for writing an iterator. Instead of hand-writing a class that tracks position, you write a function with yield statements, and the language builds the iterator object for you.
- Can two iterators walk the same collection at the same time?
- Yes, and that is a key benefit. Each iterator object keeps its own position, so two traversals never disturb each other. But be careful about modifying a collection while an iterator is walking it.
Further reading
Related Lessons
Chain of Responsibility Pattern: Pass the Request Until Someone Handles It
Learn the Chain of Responsibility pattern with a simple school leave application story, easy TypeScript and C# code, diagrams, tables, and practice tasks.
Command Pattern: Turn Every Action into an Order Slip
Learn the Command pattern through a restaurant order slip story. Simple TypeScript and C# code with undo and redo, diagrams, tables, and practice tasks.
Composite Pattern: Boxes Inside Boxes โ Treat One Thing and Many Things Alike
Learn the Composite pattern with boxes inside a courier parcel. Treat one item and a full group the same way, and add totals easily with simple recursion.
Factory Method Pattern: Let the Branch Decide the Vehicle
Learn the Factory Method design pattern with a simple Indian tiffin service story, easy TypeScript and C# code, diagrams, real examples, and practice.