-
[Design Pattern] 이터레이터 패턴 (Iterator Pattern)공부/디자인 패턴 2021. 6. 20. 20:18
이터레이터 패턴은 컬렉션의 구현 방법을 노출시키지 않고 그 안에 존재하는 모든 항목에 접근할 수 있도록 하는 패턴입니다. 이터레이터 패턴을 사용하면 컬렉션 내에 구현이 어떤지 몰라도 해당 객체에 접근해 반복 작업을 처리할 수 있습니다.
for (int i = 0; i < arr.length < i++) { System.out.println(arr[i]); }
위에서 i는 arr이라는 배열의 위치를 나타내는 변수입니다. 이러한 기능을 추상화하여 일반화 한 것을 이터레이터 패턴이라 합니다.
클래스 다이어그램
iterator: 컬렉션의 요소들을 순서대로 검색하기 위한 인터페이스
ConcreteInterface: iterator 인터페이스 구현체
Aggregate: 여러 요소들로 구성된 컬렉션 인터페이스
ConcreteAggregate: Aggregate 인터페이스 구현체
예시
여기서 책을 등록하고 순회하면서 등록한 책 목록을 출력한다고 가정합니다. 여기서 중요한 것은 자바 Iterator 라이브러리를 import하는 것이 아닌 직접 만든 Iterator 인터페이스를 import해야 합니다.
public interface Iterator { boolean hasNext(); Object next(); } public interface Aggregate { Iterator CreateIterator(); } public class Book { private final String name; public Book(String name) { this.name = name; } public String getName() { return name; } } public class BookShelfIterator implements Iterator { private final BookShelfAggregate bookShelfAggregate; private int index; public BookShelfIterator(BookShelfAggregate bookShelfAggregate) { this.bookShelfAggregate = bookShelfAggregate; this.index = 0; } @Override public boolean hasNext() { return index < bookShelfAggregate.getLength(); } @Override public Object next() { Book book = bookShelfAggregate.getBookAt(index); index++; return book; } } public class BookShelfAggregate implements Aggregate { private final Book[] books; private int last = 0; public BookShelfAggregate(int maxsize) { this.books = new Book[maxsize]; } public Book getBookAt(int index) { return books[index]; } public void appendBook(Book book) { this.books[last] = book; last++; } public int getLength() { return last; } @Override public Iterator CreateIterator() { return new BookShelfIterator(this); } } BookShelfAggregate bookShelfAggregate = new BookShelfAggregate(3); bookShelfAggregate.appendBook(new Book("자바")); bookShelfAggregate.appendBook(new Book("파이썬")); bookShelfAggregate.appendBook(new Book("golang")); System.out.println("개수 : "+bookShelfAggregate.getLength()); Iterator it = bookShelfAggregate.CreateIterator(); while(it.hasNext()){ Book book = (Book) it.next(); System.out.println(book.getName()); } //개수 : 3 //자바 //파이썬 //golang
서로 다른 집합 객체 구조에 대해서도 동일한 방법으로 접근하고 싶은 경우 사용하는 패턴이지만 실제로 쓰일지는 잘 모르겠습니다.
파이썬
파이썬의 경우, 매직 메소드로 iter와 next가 탑재되어 있어 자바보다 구현하기가 훨씬 간단합니다. BookShelf 클래스에서 Aggregate이자 Iterator 역할을 전부 처리할 수 있습니다. 만약 내부 구현이 복잡하게 들어가야 한다면 list를 상속받아 보다 쉽게 구현할 수도 있습니다.
추가로 파이썬의 iterator는 자바의 hasNext 메소드와 동일한 기능을 가진 메소드가 존재하지 않아 아래에선 커스텀하게 구현한 모습입니다.
class Book: def __init__(self, name): self._name = name @property def name(self): return self._name class BookShelf: def __init__(self): self._book = [] self._last = 0 self._current = 0 def append(self, book): self._book.append(book) self._last += 1 def length(self): return self._last def __iter__(self): return self def __next__(self): if self._current < self._last: r = self._current self._current += 1 return self._book[r] else: raise StopIteration def has_next(self): return self._current < self._last book_shelf_iterator = BookShelf() book_shelf_iterator.append(Book('자바')) book_shelf_iterator.append(Book('파이썬')) book_shelf_iterator.append(Book('golang')) print('개수: ', book_shelf_iterator.length()) for book in book_shelf_iterator: print(book.name) // 또는 has_next를 사용해 while문을 구현한 모습 // while book_shelf_iterator.has_next(): // book = book_shelf_iterator.__next__() // print(book.name) 개수: 3 자바 파이썬 golang