컬렉션의 구현 방법을 노출하지 않은 채
집합체(aggregate) 내의 모든 항목에 접근하는 방법을 제공하는 디자인 패턴
자료구조(컬렉션, 집합체)에 접근하는 기능들을 분리시켜서 캡슐화 한다.
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
위 예시에서 집합체에 접근하기 위해 사용된 i 를 추상화하여 구현한 것이 바로 반복자 패턴의 핵심이다.
public class Menu {
private String name;
public Menu(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
이름 멤버를 가지고 있는 메뉴 클래스를 예시로 들어보면,
public interface Aggregate {
public Iterator createIterator();
}
반복자를 생성해야 하는 집합체 인터페이스를 생성해주고,
public class MenuTableIterator implements Iterator<Menu> {
private MenuTable menuTable;
priavet int index = 0;
public MenuTableIterator(MenuTable menuTable) {
this.menuTable = menuTable;
}
@Override
public boolean hasNext() {
return index < menuTable.getLength();
}
@Override
public Menu next() {
return MenuTable.getMenu(this.index++);
}
}
메뉴테이블반복자 클래스를 구현해준다. 이때, 자바의 Iterator 인터페이스를 구현하는데
해당 내용에 대해서는 아래에서 추가 설명하도록 하겠다.
Iterator의 구현 메소드를 재정의해주고,
public class MenuTable implements Aggregate {
private Menu[] menus;
private menuIndex = 0;
public MenuTable(int size) {
this.menus = new Menu[size];
}
public getMenu(int index) {
return this.menus[index];
}
public void addMenu(Menu menu) {
if (this.index < this.menus.length) {
this.menus[menuIndex++] = menu;
} else {
System.out.println("메뉴판이 꽉찼습니다!");
}
}
@Override
public Iterator createIterator() {
return new MenuTableIterator(this);
}
}
메뉴테이블이 집합체(Aggregate) 인터페이스를 구현하여
반복자를 생성하는 함수를 재정의해준다.
이렇게 반복자클래슬르 구현하게 되면 메뉴테이블의 menus 배열에 접근하는 방법을 추상화시켜서 사용할 수 있다.
public static void main(String[] args) {
MenuTable menuTable = new MenuTable(5);
Menu menu1 = new Menu("김치볶음밥");
Menu menu2 = new Menu("제육볶음");
Menu menu3 = new Menu("마라탕");
Menu menu4 = new Menu("샤브샤브");
Menu menu5 = new Menu("김치찌개");
menuTable.addMenu(menu1);
menuTable.addMenu(menu2);
menuTable.addMenu(menu3);
menuTable.addMenu(menu4);
menuTable.addMenu(menu5);
// 반복자를 이용하여 접근
Iterator it = MenuTable.createIterator();
while (it.hasNext()) {
Menu menu = (Menu) it.next();
System.out.println(menu.getName();
}
// 김치볶음밥
// 제육볶음
// 마라탕
// 샤브샤브
// 김치찌개
}
이렇게 하면 MenuTable 클래스에 의존하지 않고 MenuTable의 menus의 모든 요소들에 접근할 수 있게 된다.
반복자 패턴에 대해서 정리하자면,
반복자 인터페이스와 이를 구현한 구체적 반복자를 생성하고
집합체 인터페이스에서 이 반복자를 생성하는 메소드를 구현하게 하고,
해당 집합체 인터페이스를 구현한 구체적인 집합체에서 반복자를 생성하고 해당 반복자를 통해서 구체적 집합체의 모든 요소에 접근할 수 있게 만드는 것이 반복자 패턴이다.
Iterator(반복자): Iterator 인터페이스
ConcreteIterator(구체적 반복자): 메뉴테이블반복자
Aggregate(집합체): Aggregate 인터페이스(반복자 생성 기능을 구현하게 만드는 인터페이스)
Concrete Aggregate(구체적 집합체): 메뉴테이블
JAVA8등장부터 인터페이스에서 default 메소드를 통해 메소드를 구현할 수 있다.
자바의 Iterator 인터페이스는 hasNext()와 next()함수를 반드시 재정의해서 사용해야 하지만 default로 정의된 remove와 forEachRemaining 등은 반드시 구현할 필요는 없다.
마찬가지로, Iterable 인터페이스를 잘 보면 반복자를 생성하는 함수를 구현해야 한다.(iterator())
이처럼 자바에서는 Iterator, Iterable 인터페이스를 이용하여 반복자 패턴을 구현할 수 있다.
Iterator 인터페이스는 모든 항목에 접근하는 용도
Iterable 인터페이스는 모든 요소를 가지고 추가적인 메소드를 구현하기 위해서 사용한다.