처리를 반복 할 수 있도록 내부적으로 컬렉션이나 배열을 생성하여 반복자를 제공하는 행동패턴입니다.
List 와 배열을 통해 생성하지 않고 왜 Iterator를 사용할까?
컬렉션의 종류에 상관없이 클라이언트는 사용 클래스를 인스턴스화하고 내용을 추가하기만 한다면 반복문을 사용할 수 있습니다. 이는 클라이언트가 복잡한 컬렉션을 직접 생성하는 대신 인터페이스를 통해 일관성 있게 처리할 수 있도록 합니다. 가령 일반적인 패턴에서 보이듯 어떤 클래스에서는 ArrayList 또는 배열을 사용하여 코드의 복잡성이 증가하는데 이를 일관성 있게 바꾸어주어 유지보수에 좋은 코드를 작성할 수 있도록 유도합니다.
구현은 자바 java.util 패키지의 Iterable 클래스와 Iterator 클래스를 사용하여 구현합니다.
어떤 객체의 모음의 클래스는 Iterable를 통해 구현하고 객체의 모음 클래스가 반복자를 실행할 수 있도록 실제 반복하는 클래스를 만들어 Iterator를 통해 구현시키고 해당 클래스를 객체 모음 클래스에서 리턴하도록 구현하여 Main에서는 Iterator에 접근하지 않고 바로 사용할 수 있도록 합니다.
예제 프로그램은 Book객체를 BookShelf를 만들어 객체를 모으고
BookShelf를 통해 Book 객체를 반복 순회하면서 객체를 반환 할 수 있도록 만들 것 입니다.
이렇게 하면 사용자(클라이언트) BookShelf 클래스를 인스턴스화하고 Book을 담기만 하면 어떻게 구현했던가 반복자를 사용할 수 있습니다.
먼저 Book 클래스입니다.
Book클래스는 단지 Book에 대한 정보만 담고 있어야되지요.
public class Book {
private String name;
public Book(String name){
this.name = name;
}
public String getName() {
return name;
}
}
그 다음 BookShelf입니다.
예제에서는 배열을 만들어 관리하지만 다양한 컬렉션을 이용해 담을 수도 있습니다.
public class BookShelf implements Iterable<Book> {
private Book[] books;
private int size = 0;
// 책상의 크기를 결정한다.
public BookShelf(int maxsize){
this.books = new Book[maxsize];
}
// 책을 차례로 반환하기 위해 index에 따라 반환하도록 한다.
public Book getBookAt(int index){
return books[index];
}
// 책을 등록하는 코드, Book 클래스를 받고 배열에 저장한다음 크기를 증가시킨다.
public void appendBook(Book book){
this.books[size] = book;
this.size++;
}
// 해당 크기를 반환한다. 반복하려면 크기를 알아야한다.
public int getLength(){
return this.size;
}
// 반복부분, next와 hasNext 등 기본 제공 메소드를 제공하기 위해
반복자를 상속받은 클래스를 리턴한다.
@Override
public Iterator<Book> iterator() {
return new BookShelfIterator(this);
}
}
그 다음 Iterator를 구현한 클래스를 생성합니다.
(여기서는 BookShelfIterator클래스가 그 역할을 한다.)
public class BookShelfIterator implements Iterator<Book> {
private BookShelf bookShelf;
private int index;
// 책장을 받아 해당 책장을 인스턴스 초기화한다.
public BookShelfIterator(BookShelf bookShelf) {
this.bookShelf = bookShelf;
this.index = 0; // 0부터 시작임
}
//hasNext는 책장의 길이와 index의 크기로 구분한다.
@Override
public boolean hasNext() {
if(index < bookShelf.getLength()){
return true;
}else{
return false;
}
}
//책의 현재 인덱스를 통해 book을 반환하고 index를 증가시킨다.
@Override
public Book next() {
if(!hasNext()){
throw new NoSuchElementException();
}
Book book = bookShelf.getBookAt(index);
index++;
return book;
}
}
사용부분 서두에 말한 것 처럼 책장을 만들고 책을 넣고 그냥 반복문을 사용하면 끝이다.
public class BookMain {
public static void main(String[] args) {
// 책장을 인스턴스화 하고
BookShelf bookShelf = new BookShelf(4);
// 책을 넣은 다음
bookShelf.appendBook(new Book("Around the World"));
bookShelf.appendBook(new Book("Bible"));
bookShelf.appendBook(new Book("Cinderella"));
bookShelf.appendBook(new Book("Daddy-Long"));
// 반복자를 만든 다음
Iterator<Book> iterator = bookShelf.iterator();
// 반복시키면 끝, 배열인지 List인지 고민 없이 사용함
while (iterator.hasNext()) {
Book book = iterator.next();
System.out.println(book.getName());
}
System.out.println();
for(Book book : bookShelf) {
System.out.println(book.getName());
}
System.out.println();
}
}
컬렉션의 내부 구조를 숨기고 싶을 때
컬렉션의 요소들을 순차적으로 처리할 필요가 있을 때
여러 가지 순회 방법을 제공해야 할 때
동일한 인터페이스로 다양한 컬렉션을 순회해야 할 때
책임 분리
일관된 인터페이스 제공
내부 구현의 은닉
확장성