Iterator
Iterator는 컬렉션의 내부 구조를 노출하지 않으면서 그 요소들을 하나씩 순서대로 접근할 수 있게 해주는 행위 패턴입니다. 클라이언트는 next()와 hasNext() 같은 공통 인터페이스만 사용하고, 실제로 데이터가 배열에 있는지, 트리에 있는지, 해시맵에 있는지 신경 쓰지 않습니다.
▶아키텍처 다이어그램
🔍 구조 다이어그램점선 애니메이션은 데이터 또는 요청의 흐름 방향을 나타냅니다
리스트를 순회하는 건 간단합니다. 인덱스를 하나씩 올리면 됩니다. 그런데 트리나 그래프처럼 비선형 자료구조를 순회하려면 깊이 우선인지, 너비 우선인지, 어떤 조건으로 필터링할지 순회 방법 자체가 달라집니다. 이 순회 로직을 컬렉션 클래스 안에 넣으면 자료구조의 핵심 책임이 흐려지고, 새로운 순회 방식이 필요할 때마다 컬렉션을 수정해야 합니다. 클라이언트 코드가 컬렉션의 내부 구조를 알아야만 순회할 수 있다면, 자료구조를 바꾸는 순간 순회하던 모든 코드가 함께 깨집니다.
객체지향 프로그래밍 초기부터 컬렉션은 가장 흔한 데이터 구조였습니다. 컬렉션 종류가 다양해지면서 문제가 드러났습니다. 배열, 연결 리스트, 트리, 그래프, 스택, 큐를 다루는 코드가 각각 다른 순회 방식을 썼고, 자료구조를 교체하면 순회 로직까지 전부 다시 짜야 했습니다. GoF(Gang of Four)가 Iterator를 패턴으로 정리한 이유는 순회라는 행위가 자료구조만큼 자주 바뀌는데도 둘이 한 덩어리로 묶여 있었기 때문입니다. 오늘날 Java의 Iterator, Python의 __iter__/__next__, JavaScript의 Symbol.iterator처럼 대부분의 언어가 이터레이터를 1급 기능으로 내장한 것은 이 패턴이 그만큼 보편적인 필요를 해결하기 때문입니다.
Iterator 패턴은 두 축으로 구성됩니다. 하나는 컬렉션(Aggregate) 축이고 다른 하나는 이터레이터 축입니다. 컬렉션은 자신의 요소를 저장하고 관리하는 책임만 집니다. 순회가 필요하면 createIterator() 메서드로 이터레이터 객체를 생성해 넘깁니다. 이터레이터는 현재 위치를 기억하는 커서 역할을 합니다. next()를 호출하면 현재 요소를 반환하고 커서를 다음으로 옮기며, hasNext()로 끝에 도달했는지 확인합니다. 핵심은 커서 상태가 이터레이터 안에 있다는 점입니다. 같은 컬렉션에 이터레이터를 여러 개 만들면 각자 독립적인 위치에서 순회할 수 있습니다. 자료구조가 트리에서 그래프로 바뀌어도 클라이언트 코드는 next()와 hasNext()만 쓰면 되니 영향을 받지 않습니다.
Iterator와 Composite는 둘 다 복잡한 구조를 다루지만 해결하는 문제가 다릅니다. Composite는 트리 구조 자체를 재귀적으로 구성하고 단일 객체처럼 다루는 데 초점이 있고, Iterator는 그런 구조를 어떤 순서로 순회할지를 분리하는 데 초점이 있습니다. 실제로 Composite 패턴으로 만든 트리를 Iterator로 순회하는 조합이 자주 쓰입니다. Visitor와도 비교됩니다. 둘 다 컬렉션의 요소를 하나씩 방문하지만, Iterator는 순회 순서와 접근 방식에 집중하고 Visitor는 각 요소에 어떤 연산을 적용할지에 집중합니다. Iterator가 '어떤 순서로 꺼낼까'라면 Visitor는 '꺼낸 뒤 무엇을 할까'입니다.
이터레이터는 대부분의 현대 언어에 이미 내장되어 있어서 직접 패턴을 구현할 일은 드뭅니다. 하지만 패턴을 이해해야 하는 순간은 여전히 존재합니다. 커스텀 자료구조를 만들 때가 대표적입니다. 예를 들어 조직도를 트리로 표현한 뒤, 부서별 순회와 직급별 순회가 필요하면 같은 트리에 서로 다른 이터레이터를 붙이는 것이 자연스러운 설계입니다. 데이터베이스 쿼리 결과를 한꺼번에 메모리에 올리지 않고 한 행씩 가져오는 커서 기반 순회도 이터레이터의 변형입니다. 페이지네이션 API를 래핑해 호출자에게 연속된 스트림처럼 보여주는 것도 같은 원리입니다. 패턴이 맞지 않는 경우도 있습니다. 요소를 순서대로 하나씩 접근할 필요가 없거나, 순회 중에 컬렉션 자체를 빈번하게 변경해야 하는 상황에서는 이터레이터의 커서 상태 관리가 오히려 복잡성을 더합니다.