책너두 (헤드 퍼스트 디자인 패턴) 27일차 (~373p)
- Book/헤드 퍼스트 디자인 패턴
- 2023. 8. 3.
요약
- 반복자 패턴과 컴포지트 패턴
- 반복자 패턴
- 객체마을 식당 메뉴에 반복자 추가하기
- 객체마을 식당 메뉴에서 반복자 사용하기
- 종업원 코드에 반복자 적용하기
- 반복자 패턴의 특징 알아보기
- 인터페이스 개선하기
- java.util.Iterator 적용하기
- 반복자 패턴의 정의
- 반복자 패턴의 구조 알아보기
- 반복자 패턴
메모
반복자 패턴
- 반복자(iterator) 패턴이라고 부름.
- Iterator 인터페이스에 의존함.
- hasNext() 메소드를 사용하면 반복 작업을 적용할 대상이 더 있는지 확인 가능
- next() 메소드는 다음 객체를 리턴함.
- 이 인터페이스가 있으면 배열, 리스트, 해시 테이블은 물론, 모든 종류의 객체 컬렉션에 반복자를 구현할 수 있음.
객체마을 식당 메뉴에 반복자 추가하기
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
- 두 클래스의 인터페이스가 완전히 똑같음에도 아직 인터페이스 통일하지는 않음.
- 2개의 구상 메뉴 클래스에 묶여 있음.
인터페이스 개선하기
- 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 인스턴스를 만들 수 있어야 함.
- ConcreateIterator 는 반복 작업 중에 현재 위치를 관리하는 일을 맡음.
- Iterator 인터페이스는 모든 반복자가 구현해야 하는 인터페이스를 제공함.
'Book > 헤드 퍼스트 디자인 패턴' 카테고리의 다른 글
책너두 (헤드 퍼스트 디자인 패턴) 29일차 (~398p) (0) | 2023.08.07 |
---|---|
책너두 (헤드 퍼스트 디자인 패턴) 28일차 (~386p) (0) | 2023.08.05 |
책너두 (헤드 퍼스트 디자인 패턴) 26일차 (~360p) (0) | 2023.08.03 |
책너두 (헤드 퍼스트 디자인 패턴) 25일차 (~345p) (0) | 2023.08.02 |
책너두 (헤드 퍼스트 디자인 패턴) 24일차 (~334p) (0) | 2023.07.30 |