Composite and Iterator Design Pattern Combination in TypeScript

Mohammed Muwanga
3 min read4 days ago
Composite and Iterator Design Pattern Combination in TypeScript — Mohammed Muwanga — Web Development

When ever you’re dealing with hierarchical structures requiring efficient traversal, then think of the powerful combination of the Iterator Pattern an the Composite Pattern. Here, the Composite Pattern represents individual objects and collections as tree-like structures and treats them uniformly. Take a case for an office furniture catalog with categories like chairs, desks, and storage units, each containing multiple subcategories or products. Once we introduce in the Iterator Pattern, we simplify a way to navigate through these nested subcategories without exposing the underlying implementation. This means there is no need to write recursive loops when accessing furniture items nested within. The good thing here is abstracting the traversal logic while sequentially retrieving each product no matter its depth in the hierarchy. It would be great if we also implemented it when building our custom package in Laravel 11

Here’s how you’d want to combine them:

Scenario: Managing Office Furniture Hierarchy

  • Composite Pattern: Represents office furniture store as a tree structure where Workstation (composite) contains Desks, Chairs, and Cabinets (leaf nodes).
  • Iterator Pattern: The guy to easy traverse our furniture hierarchy without exposing its internal structure.

Step 1: Define the Composite Pattern

1.1 Base Component Interface

// Component interface representing office furniture
interface OfficeFurniture {
getName(): string;
getPrice(): number;
}

1.2 Leaf Components (Individual Furniture Items)

Desk Class

// Concrete class representing a Desk
class Desk implements OfficeFurniture {
constructor(private name: string, private price: number) {}

getName(): string {
return this.name;
}

getPrice(): number {
return this.price;
}
}

Chair Class

// Concrete class representing a Chair
class Chair implements OfficeFurniture {
constructor(private name: string, private price: number) {}

getName(): string {
return this.name;
}

getPrice(): number {
return this.price;
}
}

Cabinet Class

// Concrete class representing a Cabinet
class Cabinet implements OfficeFurniture {
constructor(private name: string, private price: number) {}

getName(): string {
return this.name;
}

getPrice(): number {
return this.price;
}
}

1.3 Composite Class (Workstation to Group Multiple Furniture Items)

// Composite class representing a Workstation
class Workstation implements OfficeFurniture {
private furnitureItems: OfficeFurniture[] = [];

constructor(private name: string) {}

add(furniture: OfficeFurniture): void {
this.furnitureItems.push(furniture);
}

remove(furniture: OfficeFurniture): void {
this.furnitureItems = this.furnitureItems.filter(item => item !== furniture);
}

getName(): string {
return this.name;
}

getPrice(): number {
return this.furnitureItems.reduce((total, item) => total + item.getPrice(), 0);
}

getFurniture(): OfficeFurniture[] {
return this.furnitureItems;
}
}

Step 2: Implement the Iterator Pattern

2.1 Define the Iterator Interface

// Iterator interface for office furniture traversal
interface FurnitureIterator {
hasNext(): boolean;
next(): OfficeFurniture;
}

2.2 Implement the Concrete Iterator

// Concrete iterator to traverse composite furniture structure
class WorkstationIterator implements FurnitureIterator {
private index = 0;

constructor(private furnitureItems: OfficeFurniture[]) {}

hasNext(): boolean {
return this.index < this.furnitureItems.length;
}

next(): OfficeFurniture {
return this.furnitureItems[this.index++];
}
}

2.3 Iterable Collection Interface

// Interface for collections that can create iterators
interface IterableCollection {
createIterator(): FurnitureIterator;
}

2.4 Implement IterableCollection in Workstation

// Workstation class now supports iteration
class IterableWorkstation extends Workstation implements IterableCollection {
createIterator(): FurnitureIterator {
return new WorkstationIterator(this.getFurniture());
}
}

Step 3: Putting It All Together

// Create individual office furniture items
const chair1 = new Chair("ErgoChair", 150);
const chair2 = new Chair("LuxuryChair", 250);
const desk1 = new Desk("StandingDesk", 500);
const cabinet1 = new Cabinet("FileCabinet", 300);

// Create a composite Workstation and add items
const workstation = new IterableWorkstation("Executive Workstation");
workstation.add(chair1);
workstation.add(chair2);
workstation.add(desk1);
workstation.add(cabinet1);

// Create an iterator for the workstation
const iterator = workstation.createIterator();

// Iterate through furniture items in the workstation
console.log(`Furniture in ${workstation.getName()}:`);
while (iterator.hasNext()) {
const furniture = iterator.next();
console.log(`- ${furniture.getName()} (${furniture.getPrice()})`);
}

console.log(`Total Cost: ${workstation.getPrice()}`);

🔹 Expected Output

Furniture in Executive Workstation:
- ErgoChair (150)
- LuxuryChair (250)
- StandingDesk (500)
- FileCabinet (300)
Total Cost: 1200

Why This Combination Works Well

Scalability → New furniture types can be added without modifying existing code.
Flexibility → Workstations can be nested, and iterators traverse them uniformly. It means this, if this system needs to show only in-stock items from a deeply nested structure, a filtering iterator can return relevant products efficiently. This also creates different types of iterators for various needs. These include;

  • Breadth-first or depth-first traversal (depending on whether you want to explore categories first or individual products).
  • Filtering iterators that return only specific types of products (e.g., all ergonomic chairs).
  • Lazy-loading iterators to fetch data on demand, improving performance for large catalogs.

Encapsulation → The iteration logic is separate from the furniture structure.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Mohammed Muwanga
Mohammed Muwanga

Written by Mohammed Muwanga

Web Design, Development, SEO and Ergonomics

No responses yet

Write a response