π§© Iterator Pattern
β Intentβ
- Abstract the traversal of a collection so that the iteration logic is reusable and separate from processing logic
- Focus on the "traversal mechanism", not the "business logic"
β Motivationβ
- If your
Facade
orProxy
involves iteration or sequences of actions (e.g. multi-step flows), you can decouple that traversal logic using an iterator - Replaces repeated
for
loops scattered across multiple classes
β When to Useβ
- You have a sequence of steps or items (auth, load, audit, etc.)
- You want to encapsulate iteration and make the flow reusable and maintainable
β Code Exampleβ
- TypeScript
- PHP
- Python
interface Step {
execute(context: Record<string, any>): void;
}
class AuthStep implements Step {
execute(context: Record<string, any>): void {
console.log(`γ¦γΌγΆγΌθͺθ¨Ό: ${context.userId}`);
context.authenticated = true;
}
}
class LoadProfileStep implements Step {
execute(context: Record<string, any>): void {
if (!context.authenticated) throw new Error("ζͺθͺθ¨Ό");
console.log(`γγγγ£γΌγ«εεΎ: ${context.userId}`);
context.profile = { name: "Hiroshi", id: context.userId };
}
}
class AuditStep implements Step {
execute(context: Record<string, any>): void {
console.log("[η£ζ»γγ°] γγγγ£γΌγ«θ‘¨η€Ί");
}
}
class UserProfileFlow {
private steps: Step[] = [];
constructor() {
this.steps = [new AuthStep(), new LoadProfileStep(), new AuditStep()];
}
execute(userId: string) {
const context: Record<string, any> = { userId };
for (const step of this.steps) {
step.execute(context);
}
console.log(context.profile);
}
}
// ε©η¨δΎ
const flow = new UserProfileFlow();
flow.execute("user-123");
<?php
interface Step {
public function execute(array &$context): void;
}
class AuthStep implements Step {
public function execute(array &$context): void {
echo "γ¦γΌγΆγΌθͺθ¨Ό: {$context['userId']}\n";
$context['authenticated'] = true;
}
}
class LoadProfileStep implements Step {
public function execute(array &$context): void {
if (!($context['authenticated'] ?? false)) {
throw new Exception("ζͺθͺθ¨Ό");
}
echo "γγγγ£γΌγ«εεΎ: {$context['userId']}\n";
$context['profile'] = ['name' => 'Hiroshi', 'id' => $context['userId']];
}
}
class AuditStep implements Step {
public function execute(array &$context): void {
echo "[η£ζ»γγ°] γγγγ£γΌγ«θ‘¨η€Ί\n";
}
}
class UserProfileFlow {
private array $steps;
public function __construct() {
$this->steps = [new AuthStep(), new LoadProfileStep(), new AuditStep()];
}
public function execute(string $userId): void {
$context = ['userId' => $userId];
foreach ($this->steps as $step) {
$step->execute($context);
}
print_r($context['profile']);
}
}
// ε©η¨δΎ
$flow = new UserProfileFlow();
$flow->execute("user-123");
from abc import ABC, abstractmethod
class Step(ABC):
@abstractmethod
def execute(self, context: dict):
pass
class AuthStep(Step):
def execute(self, context: dict):
print(f"γ¦γΌγΆγΌθͺθ¨Ό: {context['user_id']}")
context['authenticated'] = True
class LoadProfileStep(Step):
def execute(self, context: dict):
if not context.get('authenticated'):
raise Exception("ζͺθͺθ¨Ό")
print(f"γγγγ£γΌγ«εεΎ: {context['user_id']}")
context['profile'] = {"name": "Hiroshi", "id": context['user_id']}
class AuditStep(Step):
def execute(self, context: dict):
print("[η£ζ»γγ°] γγγγ£γΌγ«θ‘¨η€Ί")
class UserProfileFlow:
def __init__(self):
self.steps: list[Step] = [AuthStep(), LoadProfileStep(), AuditStep()]
def execute(self, user_id: str):
context = {"user_id": user_id}
for step in self.steps:
step.execute(context)
print(context["profile"])
# ε©η¨δΎ
flow = UserProfileFlow()
flow.execute("user-123")
β Explanationβ
This code uses the Iterator
pattern to define a user flow made of sequential processing steps like authentication, profile loading, and audit logging. Each step is independent and follows a shared interface.
This approach improves maintainability, allows future extension (new steps), and isolates control flow from implementation details.
1. Iterator Pattern Overviewβ
-
Aggregate: A collection that exposes a unified interface to iterate over its elements
- Here:
UserProfileFlow
- Here:
-
Iterator: Mechanism to traverse the elements of the collection
- Here:
for...of
loop over thesteps
list
- Here:
-
Concrete Element: The individual elements of the collection
- Here:
AuthStep
,LoadProfileStep
,AuditStep
- Here:
2. Key Classes and Responsibilitiesβ
-
Step
- Common interface for all steps with an
execute(context: object)
method
- Common interface for all steps with an
-
AuthStep
,LoadProfileStep
,AuditStep
- Concrete implementations of
Step
, each encapsulating a part of the logic:AuthStep
: Verifies authenticationLoadProfileStep
: Loads user profileAuditStep
: Logs the access
- Concrete implementations of
-
UserProfileFlow
- Aggregates all steps
execute()
method traverses each step and applies it sequentially
3. UML Class Diagramβ
4. Benefits of the Iterator Patternβ
- Clear control flow: Easy to understand and maintain ordered execution of steps
- Extensible: New steps can be added without modifying the flow logic
- Reusability: Common iteration logic is centralized and separated from business rules
This design is particularly effective when working with flows or pipelines composed of multiple discrete stages. It keeps logic modular and enables consistent iteration across different contexts.