Shong Studio의 정보 창고

[디자인 패턴] Iterator Pattern (반복자 패턴) - 직관적인 설명 & 예시 본문

디자인 패턴

[디자인 패턴] Iterator Pattern (반복자 패턴) - 직관적인 설명 & 예시

Shong Studio 2024. 3. 25. 23:26
728x90
반응형

Iterator Pattern(반복자 패턴)이란?

Iterator를 사용하여 컨테이너를 가로지르며 컨테이너의 요소들에 접근하는 디자인 패턴
이터레이터 패턴을 사용하면 집합체(list, hashtable, vector 등) 내에서 어떤 식으로 일이 처리되는지 몰라도 그 안에 들어있는 항목들에 대해서 반복작업을 수행 할 수 있다.

Java에서는 Iterator기능을 라이브러리로 제공해주고 있다. 그래서 은연중 여러분은 Iterator를 사용하고 있었을 수 있습니다.

 

 

Iterator Pattern을 사용해야하는 이유는?

집합체 내에 있는 Data들이 다른 방식으로 출력해야한다면 코드의 일관성을 떨어트리고 규모가 커지거나 복잡해지면 비용 증가로 이어질 수 있습니다.

 

 

Iterator Pattern을 어떻게 사용하는지 알아보자.

  • 구조

Iterator Pattern Class diagram

  • 예시

팬케이크 가게의 메뉴와 디너 메뉴 Class를 만들어서 MenuItem을 정의합니다.

 

1. 팬케이크 가게 클래스에서는 menuItems를 List 클래스를 이용하고,

2. 디너 메뉴 클래스에서는 menuItems를 배열[]을 이용하였습니다.

 

때문에 menuItems를 추출하는 방법은 각기 다른 문법이 사용되어야합니다.

이럴 때 Iterator 인터페이스를 사용하여 통용시킬 수 있습니다.

public class PancakeHouseMenu {
    List<MenuItem> menuItems;
    
    public PancakeHouseMenu() {
        menuItems = new ArrayList<>();
        
        addItem("K&B 팬케이크 세트", "스크램블 에그와 토스트가 곁들어진 팬케이크", true, 2.99);
        addItem("레귤러 팬케이크 세트", "달걀 프라이와 소시지가 곁들어진 팬케이크", false, 2.99);
        addItem("블루베리 팬케이크", "블루베리와 블루베리 시럽으로 만든 팬케이크", true, 3.49);
        addItem("와플", "블루베리나 딸기를 올릴 수 있는 와플", true, 3.59);
    }
    
    public void addItem(String name, String description, boolean vegetarian, double price) {
        MenuItem menuItem = new MenuItem(name, description, vegeterian, price);
        menuItems.add(menuItem);
    }
    
    public ArrayList<MenuItem> getMenuItems() {
        return menuItems;
    }
}
public class DinerMenu {
    static final int MAX_ITEMS = 6;
    int numberOfItems = 0;
    MenuItem[] menuItems;
    
    public PancakeHouseMenu() {
        menuItems = new MenuItem[MAX_ITEMS];
        
        addItem("채식주의자용 BLT", "통밀, 콩고기 베이컨, 상추, 토마토", true, 2.99);
        addItem("BLT", "통밀, 베이컨, 상추, 토마토", false, 2.99);
        addItem("오늘의 스프", "감자 샐러드와 오늘의 스프", true, 3.49);
        addItem("핫도그", "사워크라우트, 양념, 양파, 치즈", true, 3.59);
    }
    
    public void addItem(String name, String description, boolean vegetarian, double price) {
        MenuItem menuItem = new MenuItem(name, description, vegeterian, price);
        
        if (numberOfItems >= MAX_ITEMS) {
            System.err.println("메뉴가 꽉 차 더 이상 추가할 수 없습니다.");
        } else {
            menuItems[numberOfItems ] = menuItem;
            numberOfItems += 1;
        }
    }
    
    public MenuItem[] getMenuItems() {
        return menuItems;
    }
}

 

위의 PancakeHouseMenu와 DinerMenu의 메소드에 Iterator를 create하는 메소드를 추가합니다.

1. PancakeHouseMenu에서는 List클래스를 사용하고 있는데 Java 컬렉션에서는 iterator 기능을 제공하고 있어서

return menuItems.iterator(); 뿐만으로 Iterator를 반환할 수 있습니다.

 

2. DinerMenu에서는 배열[]을 사용했기 때문에 Java 컬렉션에서 지원하는 iterator기능을 사용하지 못하기 때문에

DinerMenuIterator를 따로 구현해서 next(), hasNext() 메소드를 구현해줍시다.

public Iterator<MenuItem> createIterator() {
    return menuItems.iterator();				// Java 컬렉션에서 제공하는 기본 Iterator
}
public Iterator createIterator() {
    return new DinerMenuIterator(menuItems);
}
public class DinerMenuIterator implements Iterator<MenuItem> {
    MenuItem[] items;
    int position = 0;
    
    public DinerMenuIterator(MenuItem[] items) {
        this.items = items;
    }
    
    public MenuItem next() {
        MenuItem menuItem = items[position];
        position += 1;
        return menuItem;
    }
    
    public boolean hasNext() {
        if (position >= items.length || items[position] == null) {
            return false;
        } else {
            return true;
        }
    }
    
    public void remove() {
        throw new UnsupportedOperationException("메뉴 항목을 지울 수 없습니다.");
    }
}

 

아래 코드는 Client 부분이 되겠는데요.

printMenu 내부에서 createIterator()를 이용해서 Iterator<MenuItem>을 반환받고 같은 방식으로 처리하는 것을 보실 수 있습니다. 이것이 Iterator Pattern 입니다.

public class Waitress {
    Menu pancakeHouseMenu;
    Menu dinerMenu;
    
    public Waitress(Menu pancakeHouseMenu, Menu dinerMenu) {
        this.pancakeHouseMenu = pancakeHouseMenu;
        this.dinerMenu = dinerMenu;
    }
    
    public void printMenu() {
        Iterator<MenuItem> pancakeIterator = pancakeHouseMenu.createIterator();
        Iterator<MenuItem> dinerIterator = dinerMenu.createIterator();
        System.out.println("MENU");
        printMenu(pancakeIterator);
        printMenu(dinerIterator);
    }
    
    private void printMenu(Iterator iter) {
        while (iter.hasNext()) {
            MenuItem menuItem = iter.next();
            System.out.print(menuItem.getName() + ", ");
        	...
        }
    }
}
728x90
반응형