반복자 패턴 Iterator Pattern
반복자 패턴
- 컬렉션의 구현 방법을 노출하지 않으며 집합 내 모든 항목에 접근하는 패턴
- 리스트 및 반복문을 단순화하여 순회하는 방식.
- list는 add, set, size, clear 등 다양한 메서드를 제공
- iterator는 hasNext와 next등 단순한 메서드만 제공
- 클라이언트는 집합 자료구조(컬렉션, 배열, 컴포짓 등)를 이터레이터로만 받는다. 곧 집합 자료구조를 이터레이터로 구현해야 한다.
- 클라이언트는 집합에 대한 정렬, 필터링이 어렵다. 그저 next(), hasNext() 정도의 메서드만 사용 가능하다. 그러므로 정렬 및 필터링이 필요한 경우 이터레이터 구현 과정에서 적합한 로직을 작성해야 한다.
예제
- JobDistributor은 집합을 멀티 스레드를 사용해 작업을 병렬 처리하기 위한 코드이다.
execute(List<String> list)
,execute(PriorityQueue<String> list)
등 수많은 컬렉션에 대응하는 메서드를 구현하는 것보다,execute(Iterator<String> list)
api 한 개를 공개하는 것이 더 간단하고 명확하다.- 자바에서는 이터레이터 자료구조 인터페이스 Iterator를 이미 내장하고 있다. 그리고 컬렉션은 이미 Iterator로 변환하는 메서드를 기본적으로 제공한다. 아래는 자바 Iterator 인터페이스를 사용하는 예제이다.
PriorityQueue<String> queue = new PriorityQueue<>();
queue.add("축구하기");
queue.add("청소하기");
queue.add("설거지하기");
ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("공부하기");
arrayList.add("산책하기");
JobDistributor.execute(queue.iterator());
JobDistributor.execute(arrayList.iterator());
public class JobDistributor {
public static void execute(Iterator<String> jobs){
while(jobs.hasNext()){
String j = jobs.next();
new Thread(() -> {
System.out.printf("일꾼 %s가 %s 작업 진행 중!\n", Thread.currentThread().getName(), j);
sleep(50);
System.out.printf("일꾼 %s가 %s 작업 진행 완료!\n", Thread.currentThread().getName(), j);
}).start();
}
}
}
자바와 이터레이터
- 자바의 대표적인 이터레이터 인터페이스는 java.util.Enumeration과 java.util.Iterator이다. 현재는 Iterator만 사용한다.
- Iterator는 forEachRemaining 메서드를 통한 함수형 인터페이스 사용 가능하다.
IO와 이터레이터
- 특정 데이터를 메모리로 호출할 때 두 가지 방법을 생각할 수 있다.
- 메모리 공간을 크게 할당하여 모든 데이터를 한 번에 읽는다. 데이터를 집합으로 만들고 제어한다.
- 메모리 공간을 작게 할당한다. 원소 하나씩 호출하고 사용 완료하면 다른 원소로 덮어 쓴다.
- IO API는 위의 두 가지 전략 중 하나를 제공하거나 두 개 모두 제공한다. Java StAX (Streaming API for XML)는 XML의 태그를 읽을 때 앞서 두 가지의 전략을 사용하며 선택 가능하다.
- 전자는 메모리를 많이 사용하는 대신 사용성이 좋다. 후자는 메모리를 적게 사용하지만 많은 기능을 제공하기 어렵다.
참조
- 백기선, 디자인 패턴 강의(https://www.inflearn.com/course/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4)
- O’Reilly, “헤드 퍼스트 디자인 패턴”