// ❌ 나쁜 예: 서로 다른 자료구조를 사용하는 메뉴들
public class PancakeHouseMenu {
ArrayList<MenuItem> menuItems; // ArrayList 사용
}
public class DinerMenu {
MenuItem[] menuItems; // 배열 사용
}
// 메뉴 출력 코드
ArrayList breakfastItems = pancakeHouseMenu.getMenuItems();
MenuItem[] lunchItems = dinerMenu.getMenuItems();
// 각각 다른 방식으로 순회해야 함
for (int i = 0; i < breakfastItems.size(); i++) {
MenuItem item = (MenuItem)breakfastItems.get(i);
}
for (int i = 0; i < lunchItems.length; i++) {
MenuItem item = lunchItems[i];
}
문제점:
public interface Iterator {
boolean hasNext(); // 다음 요소가 있는지 확인
Object next(); // 다음 요소 반환
}
왜 Interface인가?
public interface Menu {
Iterator createIterator(); // Iterator 생성
}
왜 Interface인가?
느슨한 결합 (Loose Coupling)
// ✅ 클라이언트는 인터페이스만 의존
public class Waitress {
Menu menu; // 구체적인 메뉴가 아닌 인터페이스에 의존
public void printMenu() {
Iterator iterator = menu.createIterator();
while (iterator.hasNext()) {
MenuItem item = (MenuItem) iterator.next();
}
}
}
다중 구현 가능
// ✅ 한 클래스가 Menu이면서 다른 역할도 가능
public class CafeMenu implements Menu, Serializable {
// Menu 기능과 직렬화 기능 동시 제공
}
단일 책임 원칙 (Single Responsibility)
Menu (Aggregate) ────────> Iterator
(컬렉션을 가진 객체) (순회 담당 객체)
- createIterator() 제공
- 내부 자료구조 캡슐화
- Iterator를 통해서만 접근 허용
핵심 개념:

// Iterator 인터페이스
public interface Iterator {
boolean hasNext();
Object next();
}
// Menu(Aggregate) 인터페이스
public interface Menu {
Iterator createIterator();
}
public class DinerMenuIterator implements Iterator {
MenuItem[] items;
int position = 0; // 현재 위치
public DinerMenuIterator(MenuItem[] items) {
this.items = items;
}
// 다음 요소 반환
public Object next() {
MenuItem menuItem = items[position];
position++;
return menuItem;
}
// 다음 요소가 있는지 확인
public boolean hasNext() {
if (position >= items.length || items[position] == null) {
return false;
}
return true;
}
}
// 배열 기반 메뉴
public class DinerMenu implements Menu {
static final int MAX_ITEMS = 6;
int numberOfItems = 0;
MenuItem[] menuItems;
public DinerMenu() {
menuItems = new MenuItem[MAX_ITEMS];
addItem("Vegetarian BLT", "Bacon with Lettuce & tomato", true, 2.99);
addItem("BLT", "Bacon with Lettuce & tomato", false, 2.99);
}
public void addItem(String name, String description,
boolean vegetarian, double price) {
MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
if (numberOfItems >= MAX_ITEMS) {
System.err.println("Sorry, menu is full!");
} else {
menuItems[numberOfItems] = menuItem;
numberOfItems++;
}
}
// Iterator 생성 (핵심!)
public Iterator createIterator() {
return new DinerMenuIterator(menuItems);
}
}
// ArrayList 기반 메뉴
public class PancakeHouseMenu implements Menu {
ArrayList<MenuItem> menuItems;
public PancakeHouseMenu() {
menuItems = new ArrayList<MenuItem>();
addItem("Pancake Breakfast", "Pancakes with eggs", false, 2.99);
addItem("Blueberry Pancakes", "Pancakes with blueberries", true, 3.49);
}
public void addItem(String name, String description,
boolean vegetarian, double price) {
MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
menuItems.add(menuItem);
}
// ArrayList는 이미 iterator() 제공
public Iterator createIterator() {
return new PancakeHouseMenuIterator(menuItems);
}
}
public class Waitress {
Menu pancakeHouseMenu;
Menu dinerMenu;
// 생성자에서 메뉴들을 받음
public Waitress(Menu pancakeHouseMenu, Menu dinerMenu) {
this.pancakeHouseMenu = pancakeHouseMenu;
this.dinerMenu = dinerMenu;
}
// 모든 메뉴 출력
public void printMenu() {
Iterator pancakeIterator = pancakeHouseMenu.createIterator();
Iterator dinerIterator = dinerMenu.createIterator();
System.out.println("MENU\n----\nBREAKFAST");
printMenu(pancakeIterator);
System.out.println("\nLUNCH");
printMenu(dinerIterator);
}
// 통일된 방식으로 순회 (핵심!)
private void printMenu(Iterator iterator) {
while (iterator.hasNext()) {
MenuItem menuItem = (MenuItem) iterator.next();
System.out.print(menuItem.getName() + ", ");
System.out.print(menuItem.getPrice() + " -- ");
System.out.println(menuItem.getDescription());
}
}
}
public class MenuTestDrive {
public static void main(String[] args) {
Menu pancakeHouseMenu = new PancakeHouseMenu();
Menu dinerMenu = new DinerMenu();
Waitress waitress = new Waitress(pancakeHouseMenu, dinerMenu);
// 내부 구조를 몰라도 통일된 방식으로 출력!
waitress.printMenu();
}
}
MENU
----
BREAKFAST
Pancake Breakfast, 2.99 -- Pancakes with eggs
Blueberry Pancakes, 3.49 -- Pancakes with blueberries
LUNCH
Vegetarian BLT, 2.99 -- Bacon with Lettuce & tomato
BLT, 2.99 -- Bacon with Lettuce & tomato
public interface Iterator<E> {
boolean hasNext();
E next();
void remove(); // 선택적 기능
}
import java.util.Iterator;
public class PancakeHouseMenu implements Menu {
ArrayList<MenuItem> menuItems;
public Iterator createIterator() {
// ArrayList가 제공하는 iterator 사용
return menuItems.iterator();
}
}
public class CafeMenu implements Menu {
Hashtable<String, MenuItem> menuItems;
public Iterator createIterator() {
// Hashtable의 values를 iterator로 반환
return menuItems.values().iterator();
}
}
// Iterator를 사용하지 않고도 순회 가능
ArrayList<MenuItem> items = new ArrayList<>();
for (MenuItem item : items) {
System.out.println(item.getName());
}
| 요소 | 역할 | 왜 Interface? |
|---|---|---|
| Iterator | 컬렉션 순회 방법 제공 | 다양한 순회 방식 지원 가능 |
| Aggregate(Menu) | Iterator 생성 책임 | 다양한 컬렉션 구조 지원 가능 |
| ConcreteIterator | 실제 순회 구현 | 각 자료구조에 맞는 순회 방식 |
| ConcreteAggregate | 실제 데이터 저장 | 내부 구조 캡슐화 |