필터 드라이버 코드를 보다보면, 이벤트 정보를 저장한 collection (list, hash table, ...) 에
접근할 일이 자주 발생하는데, 필터별로 collection 의 종류가 다른 경우가 많다.
그래서 2가지 문제가 생긴다
1) client 코드에서 이벤트 정보를 사용할때, 필터(aggregate class) 가 어떤 collection 을
쓰는 지, "내부 정보" 를 알아야 한다.
2) client 코드에서 이벤트 정보를 사용할때, 필터 갯수만큼의 반복문을 '작성' 해야 한다.
크게 고려하지 않고 client 코드를 작성하면 보통 이런 형태로 코드가 작성된다.
// client code
public class Waitress {
Menu pancakeHouseMenu;
Menu dinerMenu;
...
public void printMenu() {
// client needs to know which collection they uses internally..
ArrayList<MenuItem> breakfast = pancakeHouseMenu.getMenuItems();
MenuItem[] diner = dinerMenu.getMenuItems();
// this will be not good, since number of Menu can be 10x or 100x..
for (int i=0; i<breakfast.size(); i++) {
...
}
for (int i=0; i<diner.length; i++) {
System.out.println(diner[i].getName() + " ");
System.out.println(diner[i].getPrice() + " ");
System.out.println(diner[i].getDescription());
}
}
}
여기서, collection 을 배열에서 HashMap 로 바꾸면?
필터 코드중에서, 내부 collection 에 대한 접근을 지원하는 반복자를 분리해서,
client 에게 리턴하는 방식으로 변경한다.
이때 SRP(단일책임원칙) 을 고려해,
기존 DinerMenu class 에서 구현하지말고, 별도의 반복자 class 에서 구현한다.
// iterator code
public class DinerMenuIterator implements Iterator<MenuItem> {
MenuItem[] items;
int position = 0;
public DinerMenuIterator(MenuItem[] menus) {
this.items = menus; // items.length fixed
}
// need to implements next, hasNext, remove
public MenuItem next() {
MenuItem item = items[position];
position = position + 1;
return item;
}
public boolean hasNext() {
if (position >= items.length || items[position] = null)
return false; // null if constructor receive empty menus
else
return true;
}
public void remove() {
throw new UnsupportedOperationException("cannot delete menu");
}
}
public class DinerMenu extends Menu {
MenuItem[] menus;
...
// public MenuItem[] getMenuItems() {
public Iterator<MenuItem> getMenuItems() {
return new DinerMenuIterator(menus);
}
}
이렇게 되면,
1) MenuItem 을 다루는 법이 수정될때, DinerMenu 클래스가 바뀌고
2) 내부 collection 에 접근이 바뀔땐, DinerMenuIterator 클래스가 바뀌게 된다.
SRP 를 준수해서 별도의 반복자 class 를 생성하면 얻을수 있는 효과는 아래와 같다.
반복자 패턴적용으로 인한 변화를 class diagram 상으로 표현하면 이렇게 될 것이다.
before : client 는 ConcreteMenu 들이 리턴한 collection 에 직접 접근해야 함
after : client 는 Menu 들이 리턴한 iteartor 에게 collection 접근을 위임함.
client 가 하는 일은, collection 안에 있는 MenuItem 내용을 출력하는 일이다.
추가 Menu (ex. LunchMenu) 가 생겼을때,
before 구조에선 printMenu 코드가 변경되고, after 구조에선 printMenu 코드가 변경되지 않는다.
참고한 서적 : https://www.yes24.com/Product/Goods/108192370