우리가 코딩에서 가장 많이 쓰는 로직은 조건문 그리고 반복문일 것이다.
저번에 디자인 패턴에서 조건문(if-else 지옥)을 이야기 했으니 이번에는 반복문을 알아보자.
반복자 패턴
간단히 말하자면, 데이터 여러개를 가진 구조가 있을떄
데이터가 어떻게 저장되어 있는지는 몰라도, 처음부터 끝까지 하나씩 꺼내 볼 수 있게 해주는 방법이다.
우리가 컬렉션이라고 부르는 다양한 자료구조가 있고 저마다 접근 방식이 다르다.
Array = 인덱스로 접근
LinkedList = 노드 따라 가야함
Tree나 Graph는 탐색 알고리즘 필요
결국에는 의존성의 분리인데
클라이언트가 데이터 접근시 자료구조 바뀐다고 클라이언트 코드 바꾸지 말자는 것이다.
반복자 패턴의 구조

<출처: https://refactoring.guru/ko/design-patterns/iterator> 리팩토링 구루
일단 1번 반복자 인터페이스를 보면 반복에 필요한 공통 작업(다음 있음?, 다음꺼)을 선언한다.
이러한 반복 동작 인터페이스를 기준으로 구현된 2번 구현체에서는 실제 컬렉션 순회를 위한 구체적인 방법들이 구현된다.
3번 컬렉션 인터페이스에서는 createIterator가 존재한다.
즉 "나를 순회할 수 있는 반복자를 만들어줘"라고 요청 할 수 있는 공통 창구이다.
리턴 타입이 1번 반복자 인터페이스와 연결되어있는데, 특정 반복자를 고정하지 않기 위해서다.
4번은 이제 공통 창구와 연결될 실제 데이터를 담는 클래스(ArrayList, LinkedList) 등이 들어갈 것이다.
다만 우리는 공통의 반복자 컬렉션 인터페이스를 통해 구현되고,
반복자 인터페이스로 구현된 반복자 구현체를 연결 하는 것으로
클라이언트가 같은 코드로 다양한 컬렉션들과 반복자를 사용 할 수 있도록 한다.
우린 이미 Iterator를 쓰고 있다.
Iterator 네이밍을 보면 알겠지만, 대부분의 프레임워크에서는 반복자 패턴을 지원한다.
당장 자바도 Iterator라고 해서 컬렉션(Collection) 프레임워크에 저장된 요소를 표준호환 인터페이스를 보유하고있다.
그래서 우리는 다양한 자바의 컬렉션을 내부 구조를 알 필요 없이 일관된 방식으로 접근 할 수 있다.
List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Cherry");
// Iterator 객체 얻기
Iterator<String> iterator = list.iterator();
// 요소 순회
while (iterator.hasNext()) {
String fruit = iterator.next();
System.out.println(fruit);
// 특정 조건 시 안전하게 삭제 가능
if ("Banana".equals(fruit)) {
iterator.remove();
}
}
그럼 Iterator 구조는 몰라도 되느냐
아마도?
애초에 디자인 패턴 몰라도 개발은 한다.
그리고 무조건 디자인 패턴이 필요하다! 라는 관점도 피곤하고
다만 Iterator 대부분은 컬렉션들에 대한 최소 공통 분모를 추구할 것이다.
즉 우리가 나중에 특수한 용도에 따른 반복 패턴이 필요한 경우 설계 관점에서는 이해할 필요가 있을 것이다.