이 인터페이스가 있으면 배열, 리스트, 해시 테이블은 물론, 모든 종류의 객체 컬렉션에 반복자를 구현할 수 있음.
객체마을 식당 메뉴에 반복자 추가하기
public interface Iterator {
boolean hasNext();
MenuItem next();
}
Iterator 인터페이스를 정의함.
public class DinerMenuIterator implements Iterator {
MenuItem[] items;
int position = 0;
public DinerMenuIterator(MenuItem[] items) {
this.items = items;
}
public MenuItem next() {
MenuItem menuItem = items[position];
position position + 1;
return menuItem;
}
public boolean hasNext() {
if (position >= items.length || items[position] == null) {
return false;
} else {
return true;
}
}
}
position 필드로 반복 작업이 처리되고 있는 위치를 저장함.
MenuItem 이 배열이므로, hasNext 메소드에서 끝인지 확인하는 것 뿐만 아니라, 중간이더라도, 다음 항목이 null, 즉 원소가 없다면 false 를 던져줘야 함.
객체마을 식당 메뉴에서 반복자 사용하기
public class DinerMenu {
static final int MAX_ITEMS = 6;
int numberOfItems = 0;
MenuItem[] menuItems;
// 생성자
// addItem 메소드 호출
// getMenuItems 메소드는 더 이상 필요 없음. (이제 굳이 내부 구조를 드러내지 않아도 됨)
public Iterator createIterator() {
return new DinerMenuIterator(menuItems);
}
// 기타 메뉴 관련 메소드
}
createIterator 메소드는 Iterator 인터페이스를 리턴함.
클라이언트는 menuItem 이 어떻게 관리되는지 알 필요 없음.
그냥 반복자로 메뉴에 들어있는 항목 하나하나에 접근할 수만 있으면 됨.
종업원 코드에 반복자 적용하기
public class Waitress {
PancakeHouseMenu pancakeHouseMenu;
DinerMenu dinerMenu;
public Waitress (PancakeHouseMenu pancakeHouseMenu, DinerMenu diner Menu) {
this.pancakeHouseMenu = pancakeHouseMenu;
this.diner Menu = diner Menu;
}
public void printMenu() {
Iterator pancakeIterator = pancakeHouseMenu.createIterator();
Iterator dinerIterator = dinerMenu.createIterator();
System.out.println("\n----\n");
printMenu(pancakeIterator);
System.out.println("\n");
printMenu(dinerIterator);
}
private void printMenu(Iterator iterator) {
while (iterator.hasNext()) {
MenuItem menuItem = iterator.next();
System.out.print(menuItem.getName() + ", ");
System.out.print(menuItem.getPrice() + " -- ");
System.out.println(menuItem.getDescription());
}
}
// 기타 메소드
}
printMenu 메소드는 Iterator 를 파라미터로 받기 때문에, 메뉴가 어떤 방식으로 구현되어있든 항목에 손쉽게 접근 가능하다.
반복자 패턴의 특징 알아보기
메뉴 구현법이 캡슐화되어 있음.
종업원은 메뉴에서 메뉴 항목의 컬렉션을 어떤 식으로 저장하는지 알 필요 없음.
반복자만 구현한다면 다형성을 활용해서 어떤 컬렉션이든 1개의 순환문으로 처리할 수 있음.
종업원은 인터페이스(반복자)만 알면 됨.
Menu 인터페이스가 완전히 똑같지 않은 상태임. (구상 클래스가 그대로 각각의 역할을 함)
2개의 구상 메뉴 클래스에 묶여 있음.
PancakeHouseMenu
DinerMenu
두 클래스의 인터페이스가 완전히 똑같음에도 아직 인터페이스 통일하지는 않음.
인터페이스 개선하기
PancakeHouseMenu, DinerMenu 인터페이스가 완전히 똑같음에도 아직 인터페이스를 통일하지 않음.
java.util 에는 Iterator 인터페이스를 제공해주고 있음.
ArrayList 에는 반복자를 리턴하는 iterator() 메소드도 있음.
하지만 배열로 구현된 DinerMenu는 따로 반복자를 구현해야 함.
java.util.Iterator 적용하기
PancakeHouseMenuIterator 클래스를 지우고, PancakeHouseMenu 에 java.util.Iterator 를 임포트하고, 코드 1줄만 고치면 됨.
public Iterator<MenuItem> createIterator() {
return menuItems.iterator();
}
ArrayList의 iterator() 메소드만 호출하면 됨.
DinnerMenuIterator 의 경우, 배열로 구현되어있기 때문에 Iterator 를 구현해야 함.
위에서 구현한 DinerMenuIterator 에서 바꿀건 없고, remove 메소드만 오버라이드해서, UnsupportedOperationException 을 던져주면 됨.
public interface Menu {
public Iterator<MenuItem> createIterator();
}
메뉴 인터페이스를 통일하고, 종업원 코드를 조금만 고치면 됨.
import java.util.Iterator;
public class Waitress {
Menu pancakeHouseMenu;
Menu diner Menu;
public Waitress (Menu pancakeHouseMenu, Menu diner Menu) {
this.pancakeHouseMenu = pancakeHouseMenu;
this.diner Menu = diner Menu;
}
public void printMenu() {
Iterator<MenuItem) pancakeIterator = pancakeHouseMenu.createIterator();
Iterator<MenuItem) dinerIterator = diner Menu.createIterator();
System.out.println("MENU\n----\n");
printMenu(pancakeIterator);
System.out.println("\n");
printMenu(dinerIterator);
}
private void printMenu(Iterator iterator) {
while (iterator.hasNext()) {
MenuItem menuItem = iterator.next();
System.out.print(menuItem.getName() + ", ");
System.out.print(menuItem.getPrice() + " -- ");
System.out.println(menuItem.getDescription());
}
}
// 기타 메소드
}
PancakeHouseMenu, DinerMenu 클래스를 Menu 인터페이스로 통일함.
반복자 패턴의 정의
각 항목에 일일이 접근할 수 있게 해 주는 기능을 집합체가 아닌 반복자 객체가 책임진다는 장점도 있음.
그러면서 집합체 인터페이스와 구현이 간단해지고, 각자에게 중요한 일만을 처리할 수 있게 됨.
반복자 패턴의 구조 알아보기
Arregate 공통 인터페이스가 있으면 클라이언트는 매우 편리하게 작업을 처리할 수 있음.
ConcreteArregate 에는 객체 컬렉션이 들어있음.
그 안에 들어있는 컬렉션을 Iterator로 리턴하는 메소드를 구현함.
안에있는 객체 컬렉션을 대상으로 돌아가면서 반복 작업을 처리할 수 있게 해주는 ConcreateIterator 인스턴스를 만들 수 있어야 함.