[๋””์ž์ธํŒจํ„ด] ์ดํ„ฐ๋ ˆ์ดํ„ฐ ํŒจํ„ด (Iterator Pattern)

๋ฐ˜์‘ํ˜•
๐Ÿ’ก ์ดํ„ฐ๋ ˆ์ดํ„ฐ ํŒจํ„ด (Iterator Pattern)
์ปฌ๋ ‰์…˜ ๊ตฌํ˜„ ๋ฐฉ๋ฒ•์„ ๋…ธ์ถœ์‹œํ‚ค์ง€ ์•Š์œผ๋ฉด์„œ๋„ ๊ทธ ์ง‘ํ•ฉ์ฒด ์•ˆ์— ๋“ค์–ด์žˆ๋Š” ๋ชจ๋“  ํ•ญ๋ชฉ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•œ๋‹ค.

 

โ–  ์˜ˆ์ œ : ๋ ˆ์Šคํ† ๋ž‘ ํ•ฉ๋ณ‘

Steak ๋ ˆ์Šคํ† ๋ž‘๊ณผ Burger ๋ ˆ์Šคํ† ๋ž‘์˜ ํ•ฉ๋ณ‘์ด ๊ฒฐ์ •๋˜์—ˆ๋‹ค. ๋‘ ๋ ˆ์Šคํ† ๋ž‘์ด ํ•ฉ๋ณ‘ํ•˜๋ฉด์„œ ๋ฉ”๋‰ด๋ฅผ ํ†ต์ผํ™”ํ•˜๊ณ  ํŒ๋งคํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค.

 

(1) ๋ฌธ์ œ์ธ์‹

1. ๋‘ ๋ ˆ์Šคํ† ๋ž‘์ด ํ•ฉ์˜ํ•œ ๋ฉ”๋‰ด ํ•ญ๋ชฉ : MenuItem

/**
 * ๋‘ ๊ฐ€๊ฒŒ์˜ ํ•ฉ์˜ํ•œ ๋ฉ”๋‰ด
 */
public class MenuItem {

    String name; // ๋ฉ”๋‰ด๋ช…
    String description; // ๋ฉ”๋‰ด์„ค๋ช…
    boolean vegetarian; // ๋ฒ ์ง€ํ…Œ๋ฆฌ์–ธ ์—ฌ๋ถ€
    Long price; // ๊ฐ€๊ฒฉ

    public MenuItem(String name, String description, Boolean vegitarian, Long price) {
        this.name = name;
        this.description = description;
        this.vegetarian = vegitarian;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public String getDescription() {
        return description;
    }

    public boolean isVegetarian() {
        return vegetarian;
    }

    public Long getPrice() {
        return price;
    }

    @Override
    public String toString() {
        return "MenuItem{" +
                "name='" + name + '\'' +
                ", description='" + description + '\'' +
                ", vegetarian=" + vegetarian +
                ", price=" + price +
                '}';
    }
}

2. ๊ฐ ๋ ˆ์Šคํ† ๋ž‘์˜ ๋ฉ”๋‰ด

/**
 * ์Šคํ…Œ์ดํฌ ๋ฉ”๋‰ด : ๋ฐฐ์—ด
 */
public class SteakMenu {

    public static final int MAX_ITEMS = 5; // ์ตœ๋Œ€ ๋ฉ”๋‰ด ๊ฐฏ์ˆ˜ 5๊ฐœ
    int numberOfItems = 0;
    MenuItem[] menuItemList;

    public SteakMenu() {
        menuItemList = new MenuItem[MAX_ITEMS];
        addMenu("์•ˆ์‹ฌ ์Šคํ…Œ์ดํฌ", "์•ˆ์‹ฌ์Šคํ…Œ์ดํฌ, ๊ตฌ์šด๋ฒ„์„ฏ, ๊ตฌ์šด์–‘ํŒŒ", false, 18000);
        addMenu("T๋ณธ ์Šคํ…Œ์ดํฌ", "T๋ณธ ์Šคํ…Œ์ดํฌ, ๊ตฌ์šดํŒŒ์ธ์• ํ”Œ, ๊ตฌ์šด๋ฒ„์„ฏ", false, 20000);
        addMenu("๋“ฑ์‹ฌ ์Šคํ…Œ์ดํฌ", "๋“ฑ์‹ฌ์Šคํ…Œ์ดํฌ, ๊ตฌ์šด๋งˆ๋Š˜, ๊ตฌ์šด๊ฐ์ž", false, 15000);
        addMenu("์ฑ„๋ ์Šคํ…Œ์ดํฌ", "์ฑ„๋์Šคํ…Œ์ดํฌ, ๊ตฌ์šด๋งˆ๋Š˜, ๊ตฌ์šด์•„์ŠคํŒŒ๋ผ๊ฑฐ์Šค", false, 12000);
        addMenu("์ฝฉ๊ณ ๊ธฐ ์Šคํ…Œ์ดํฌ", "์ฝฉ๊ณ ๊ธฐ์Šคํ…Œ์ดํฌ, ๊ตฌ์šด์•„์ŠคํŒŒ๋ผ๊ฑฐ์Šค, ๊ตฌ์šด์–‘ํŒŒ, ๊ตฌ์šดํŒŒ์ธ์• ํ”Œ", true, 17000);
    }

    public void addMenu(String name, String description, boolean vegietarian, long price) {
        MenuItem menuItem = new MenuItem(name, description, vegietarian, price);

        if (numberOfItems >= MAX_ITEMS) {
            System.err.println("๋“ฑ๋กํ•  ์ˆ˜ ์žˆ๋Š” ๋ฉ”๋‰ด ๊ฐฏ์ˆ˜๋ฅผ ์ดˆ๊ณผํ–ˆ์Šต๋‹ˆ๋‹ค.");
        } else {
            menuItemList[numberOfItems] = menuItem;
            numberOfItems += 1;
        }
    }

    public MenuItem[] getMenuItemList() {
        return menuItemList;
    }

}

/**
 * ํ–„๋ฒ„๊ฑฐ ๋ฉ”๋‰ด : ๋ฆฌ์ŠคํŠธ
 */
public class BurgerMenu {
    List<MenuItem> menuItemList;

    public BurgerMenu() {
        menuItemList = new ArrayList<>();
        addItem("๋จธ์‰ฌ๋ฃธ๋ฒ„๊ฑฐ", "๋ฒ„์„ฏ, ์ฝฉ์ด ์žฌ๋ฃŒ์ธ ํŒจํ‹ฐ๋กœ ๋งŒ๋“  ๋ฒ„๊ฑฐ", true, 8000);
        addItem("์น˜ํ‚จ๋ฒ„๊ฑฐ", "์น˜ํ‚จ ๋‹ค๋ฆฌ์‚ด๋กœ ๋งŒ๋“  ๋ฒ„๊ฑฐ", false, 9000);
        addItem("ํ•œ์šฐ๋ฒ„๊ฑฐ", "1++ ํ•œ์šฐ๋กœ ๋งŒ๋“  ๋ฒ„๊ฑฐ", false, 15000);
        addItem("์ƒˆ์šฐ๋ฒ„๊ฑฐ", "์ƒˆ์šฐ๊ฐ€ ๋“ฌ๋ฟ ๋“ค์–ด๊ฐ„ ๋ฒ„๊ฑฐ", false, 10000);
        addItem("์•ผ์ฑ„๋ฒ„๊ฑฐ", "์•ผ์ฑ„๋ฅผ ํŠ€๊ฒจ ๋งŒ๋“  ๋ฒ„๊ฑฐ", true, 7000);
    }

    public void addItem(String name, String description, boolean vegetarian, long price) {
        MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
        menuItemList.add(menuItem);
    }

    public List<MenuItem> getMenuItemList() {
        return menuItemList;
    }

    @Override
    public String toString() {
        return "burgerMenu{" +
                "menuItemList=" + menuItemList +
                '}';
    }
}

๋‘ ๊ฐ€๊ฒŒ๋Š” ๋ฉ”๋‰ด ๊ตฌํ˜„ ๋ฐฉ์‹์ด ๋‹ค๋ฅด๋‹ค. Steak ๋Š” ๋ฐฐ์—ด์„ Burger ์€ ๋ฆฌ์ŠคํŠธ๋กœ ๋ฉ”๋‰ด๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ๋‹ค. ์ด๋ ‡๊ฒŒ ๊ตฌํ˜„ ๋ฐฉ์‹์ด ๋‹ค๋ฅด๋ฉด ๊ฐ ํƒ€์ž…์— ๋งž์ถฐ ๋‘ ๊ฐœ์˜ ๋ฐ˜๋ณต๋ฌธ์ด ์ž‘์„ฑ๋˜์•ผ ํ•˜๋Š” ๋ฌธ์ œ๊ฐ€๋ฐœ์ƒํ•œ๋‹ค.

 

3. ๋‘ ๋ฉ”๋‰ด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ ํด๋ž˜์Šค (์ ์›) : Clerk

public class Clerk {

    SteakMenu steakMenu; // Array
    BurgerMenu burgerMenu; // List

    public Clerk(SteakMenu steakMenu, BurgerMenu burgerMenu) {
        this.steakMenu = steakMenu;
        this.burgerMenu = burgerMenu;
    }

    public void printMenu() {
        System.out.println("===== Steak Menu =====");
        printMenu(steakMenu.getMenuItemList());
        System.out.println("===== Burger Menu =====");
        printMenu(burgerMenu.getMenuItemList());
    }
    // ๋ฐฐ์—ด๋กœ ๋œ Steak ๋ฉ”๋‰ด ์ถœ๋ ฅ๋ฐฉ์‹
    public void printMenu(MenuItem[] menus) {
        for (int i = 0; i < menus.length; i++) {
            MenuItem menu = menus[i];
            System.out.println("name = " + menu.getName() + ", price = " + menu.getPrice());
            System.out.println("description = " + menu.getDescription());
        }
    }
    // ๋ฆฌ์ŠคํŠธ๋กœ ๋œ Burger ๋ฉ”๋‰ด ์ถœ๋ ฅ๋ฐฉ์‹
    public void printMenu(List<MenuItem> menus) {
        for (MenuItem m : menus) {
            System.out.println("name = " + m.getName() + ", price = " + m.getPrice());
            System.out.println("description = " + m.getDescription());
        }
    }

    public void printVegetarianMenu() {
        printVegetarianMenu(steakMenu.getMenuItemList());
        printVegetarianMenu(burgerMenu.getMenuItemList());
    }
    // ๋ฐฐ์—ด๋กœ ๋œ Steak ์ฑ„์‹๋ฉ”๋‰ด ์ถœ๋ ฅ๋ฐฉ์‹
    public void printVegetarianMenu(MenuItem[] menus) {
        for (int i = 0; i < menus.length; i++) {
            MenuItem menu = menus[i];
            if (menu.isVegetarian()) {
                System.out.println("name = " + menu.getName() + ", price = " + menu.getPrice());
                System.out.println("description = " + menu.getDescription());
            }
        }
    }
    // ๋ฆฌ์ŠคํŠธ๋กœ ๋œ Burger ์ฑ„์‹๋ฉ”๋‰ด ์ถœ๋ ฅ๋ฐฉ์‹
    public void printVegetarianMenu(List<MenuItem> menus) {
        for (MenuItem m : menus) {
            if (m.isVegetarian()) {
                System.out.println("name = " + m.getName() + ", price = " + m.getPrice());
                System.out.println("description = " + m.getDescription());
            }
        }
    }

    public boolean isItemVegetarian(String name) {
        MenuItem[] steakMenus = steakMenu.getMenuItemList();
        List<MenuItem> burgerMenus = burgerMenu.getMenuItemList();

        if (isVegetarian(name, steakMenus)) {
            return true;
        }
        if (isVegetarian(name, burgerMenus)) {
            return true;
        }
        return false;
    }
    // ๋ฐฐ์—ด๋กœ ๋œ Steak ๋ฉ”๋‰ด์˜ ์ฑ„์‹์—ฌ๋ถ€ ํ™•์ธ ๋ฉ”์†Œ๋“œ
    private boolean isVegetarian(String name, MenuItem[] menus) {
        for (int i = 0; i < menus.length; i++) {
            MenuItem menuItem = menus[i];
            if (menuItem.getName().equals(name)) {
                if (menuItem.isVegetarian()) {
                    return true;
                }
            }
        }
        return false;
    }
    // ๋ฆฌ์ŠคํŠธ๋กœ ๋œ Burger ๋ฉ”๋‰ด์˜ ์ฑ„์‹์—ฌ๋ถ€ ํ™•์ธ ๋ฉ”์†Œ๋“œ
    private boolean isVegetarian(String name, List<MenuItem> menuItemLists) {
        for (MenuItem m : menuItemLists) {
            if (m.getName().equals(name)) {
                if (m.isVegetarian()) {
                    return true;
                }
            }
        }
        return false;
    }

}

(2) ๋ฌธ์ œ์ 

Steak ์™€ Burger ์˜ ๊ตฌํ˜„ ๋ฐฉ์‹์ด ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ๋˜‘๊ฐ™์€ ์ฒ˜๋ฆฌ๋ฅผ ๊ฐ ๋ฐฉ์‹์— ๋งž๊ฒŒ ํ•ด๊ฒฐํ•ด์ค˜์•ผ ํ•œ๋‹ค.

์ฆ‰, ๊ฐ๊ฐ์— ๋Œ€ํ•œ ๋˜‘๊ฐ™์€ ์ฒ˜๋ฆฌ (๋ฐ˜๋ณต) ๋ฅผ ์บก์Šํ™”ํ•˜์—ฌ ๋ฐ˜๋ณต์ž ์ธํ„ฐํŽ˜์ด์Šค๋กœ ํ•ด๊ฒฐํ•ด๋ณด์ž.

 

(3) ๋ฌธ์ œํ•ด๊ฒฐ

1. Menu ์ธํ„ฐํŽ˜์ด์Šค ์ƒ์„ฑ

public interface Menu {
    public Iterator createIterator();
}

2. Steak ๋ฉ”๋‰ด์™€ Burger ๋ฉ”๋‰ด์— ๊ตฌํ˜„

/**
 * ์Šคํ…Œ์ดํฌ ๋ฉ”๋‰ด : Array, Menu ์ธํ„ฐํŽ˜์ด์Šค ์‚ฌ์šฉ
 */
public class SteakMenu implements Menu {

    // ์ธ์Šคํ„ด์Šค, ์ƒ์„ฑ์ž ์ƒ๋žต (๊ธฐ์กด๊ณผ ๋™์ผ)

    // getter ๋Š” ์‚ญ์ œํ•˜์ž. ๋‚ด๋ถ€ ๊ตฌ์กฐ๋ฅผ ๋‹ค ๋“œ๋Ÿฌ๋‚ด๊ธฐ๋•Œ๋ฌธ์— ๋ถˆํ•„์š”ํ•˜๋‹ค.
//    public MenuItem[] getMenuItemList() {
//        return menuItemList;
//    }

    @Override
    public Iterator createIterator() {
        // ์Šคํ…Œ์ดํฌ ๋ฉ”๋‰ด Iterator ์ƒ์„ฑ
        return new SteakMenuIterator(menuItemList);
    }
}
/**
 * ํ–„๋ฒ„๊ฑฐ ๋ฉ”๋‰ด : ArrayList, Menu ์ธํ„ฐํŽ˜์ด์Šค ์‚ฌ์šฉ
 */
public class BurgerMenu implements Menu {

    // ์ธ์Šคํ„ด์Šค, ์ƒ์„ฑ์ž ์ƒ๋žต (๊ธฐ์กด๊ณผ ๋™์ผ)

    // getter ๋Š” ์‚ญ์ œํ•˜์ž. ๋‚ด๋ถ€ ๊ตฌ์กฐ๋ฅผ ๋‹ค ๋“œ๋Ÿฌ๋‚ด๊ธฐ๋•Œ๋ฌธ์— ๋ถˆํ•„์š”ํ•˜๋‹ค.
//    public List<MenuItem> getMenuItemList() {
//        return menuItemList;
//    }

    @Override
    public Iterator createIterator() {
        // ๋ฒ„๊ฑฐ ๋ฉ”๋‰ด Iterator ์ƒ์„ฑ
        return new BurgerMenuIterator(menuItemList);
    }
}

3. ๋ฐฐ์—ด๊ณผ ๋ฆฌ์ŠคํŠธ์˜ ๋‚ด๋ถ€๊ตฌ์กฐ๋ฅผ ํ•˜๋‚˜๋กœ ์บก์Šํ™” ํ•  Iterator ์ธํ„ฐํŽ˜์ด์Šค ์ƒ์„ฑ

public interface Iterator {
    boolean hasNext();
    MenuItem next();
}

4. Iterator ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฐ์—ด์šฉ ๋ฐ˜๋ณต์ž (ArrayIterator) , ๋ฆฌ์ŠคํŠธ์šฉ ๋ฐ˜๋ณต์ž (ArrayListIterator) ์ƒ์„ฑ

// ๋ฐฐ์—ด์šฉ ๋ฐ˜๋ณต์ž
public class ArrayIterator implements Iterator {

    MenuItem[] menuItems;
    int position;

    public ArrayIterator(MenuItem[] menuItems) {
        this.menuItems = menuItems;
    }

    @Override
    public boolean hasNext() {
        if (position >= menuItems.length || menuItems[position] == null) {
            return false;
        } else {
            return true;
        }
    }

    @Override
    public MenuItem next() {
        MenuItem menuItem = menuItems[position];
        position += 1;
        return menuItem;
    }
}
// ๋ฆฌ์ŠคํŠธ์šฉ ๋ฐ˜๋ณต์ž
public class ArrayListIterator implements Iterator {

    ArrayList<MenuItem> menuItemList;
    int position;

    public ArrayListIterator(ArrayList<MenuItem> menuItems) {
        this.menuItemList = menuItems;
    }

    @Override
    public boolean hasNext() {
        if (position >= menuItemList.size()) {
            return false;
        } else {
            return true;
        }
    }

    @Override
    public MenuItem next() {
        MenuItem menuItem = menuItemList.get(position);
        position += 1;
        return menuItem;
    }
}

5. ํด๋ผ์ด์–ธํŠธ

public class Clerk {

    Menu steakMenu;
    Menu burgerMenu;

    public Clerk(Menu steakMenu, Menu burgerMenu) {
        this.steakMenu = steakMenu;
        this.burgerMenu = burgerMenu;
    }

    public void printMenu() {
        Iterator stakeIterator = steakMenu.createIterator();
        Iterator burgerIterator = burgerMenu.createIterator();

        System.out.println("===== Steak Menu =====");
        printMenu(stakeIterator);
        System.out.println("===== Burger Menu =====");
        printMenu(burgerIterator);
    }

    public void printMenu(Iterator menuIter) {
        while (menuIter.hasNext()) {
            MenuItem menuItem = menuIter.next();
            System.out.println("name = " + menuItem.getName() + ", price = " + menuItem.getPrice());
            System.out.println("description = " + menuItem.getDescription());
        }
    }

    public void printVegetarianMenu() {
        printVegetarianMenu(steakMenu.createIterator());
        printVegetarianMenu(burgerMenu.createIterator());
    }

    public void printVegetarianMenu(Iterator iterator) {
        while (iterator.hasNext()) {
            MenuItem menuItem = iterator.next();
            if (menuItem.isVegetarian()) {
                System.out.println("name = " + menuItem.getName() + ", price = " + menuItem.getPrice());
                System.out.println("description = " + menuItem.getDescription());
            }
        }
    }

    public boolean isItemVegetarian(String name) {
        Iterator steakIter = steakMenu.createIterator();
        Iterator burgerIter = burgerMenu.createIterator();

        if (isVegetarian(name, steakIter)) {
            return true;
        }
        if (isVegetarian(name, burgerIter)) {
            return true;
        }
        return false;
    }

    private boolean isVegetarian(String name, Iterator iter) {
        while (iter.hasNext()) {
            MenuItem menuItem = iter.next();
            if (menuItem.getName().equals(name)) {
                if (menuItem.isVegetarian()) {
                    return true;
                }
            }
        }
        return false;
    }
}

Iterator ๋ฅผ ์ด์šฉํ•ด์„œ ๋ฐฐ์—ด๊ณผ ๋ฆฌ์ŠคํŠธ์˜ ๋ฐ˜๋ณต์ž๋ฅผ ์บก์Šํ™” ํ•˜๊ธฐ ์ „์—๋Š” ๊ฐ ๊ตฌํ˜„์— ๋งž๊ฒŒ ์ƒ์„ฑํ•ด์ค˜์•ผํ–ˆ๋‹ค.

 

  • ๋ฐ˜๋ณต์ž ์บก์Šํ™” ์ „
    • ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ฐฐ์—ด, ๋ฆฌ์ŠคํŠธ๊ฐ€ ๊ฐ๊ฐ ์ถœ๋ ฅ๋ฐฉ๋ฒ•์ด ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ๊ตฌํ˜„ํ•ด์•ผํ•  ์†Œ์Šค๊ฐ€ ๋งŽ์•„์ง€๊ณ  ์ง€์ €๋ถ„ํ•˜๋‹ค. 
    • // ์ „์ฒด๋ฉ”๋‰ด ์ถœ๋ ฅ ๋ฉ”์†Œ๋“œ๋“ค
      public void printMenu(MenuItem[] menus) {...}
      public void printMenu(List<MenuItem> menus) {...}
      // ์ฑ„์‹๋ฉ”๋‰ด ์ถœ๋ ฅ ๋ฉ”์†Œ๋“œ๋“ค
      public void printVegetarianMenu(MenuItem[] menus) {...}
      public void printVegetarianMenu(List<MenuItem> menus) {...}

 

  • ๋ฐ˜๋ณต์ž ์บก์Šํ™” ํ›„
    • ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ฐฐ์—ด, ๋ฆฌ์ŠคํŠธ๋ฅผ ํ•˜๋‚˜์˜ ๋ฉ”์†Œ๋“œ์—์„œ ์ถœ๋ ฅํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค.
    • // ์ „์ฒด๋ฉ”๋‰ด ์ถœ๋ ฅ ๋ฉ”์†Œ๋“œ
      public void printMenu(Iterator menuIter) {...}
      // ์ฑ„์‹๋ฉ”๋‰ด ์ถœ๋ ฅ ๋ฉ”์†Œ๋“œ
      public void printVegetarianMenu(Iterator iterator) {...}

 

์ด๋ ‡๊ฒŒ ํ•จ์œผ๋กœ์จ ์ง‘ํ•ฉ์ฒด ๋‚ด์—์„œ ์–ด๋–ค ์‹์œผ๋กœ ์ผ์ด ์ฒ˜๋ฆฌ๋˜๋Š”์ง€์— ๋Œ€ํ•ด์„œ ์ „ํ˜€ ๋ชจ๋ฅด๋Š” ์ƒํƒœ์—์„œ๋„ ๊ทธ ์•ˆ์— ๋ชจ๋“  ํ•ญ๋ชฉ๋“ค์— ๋Œ€ํ•ด์„œ ๋ฐ˜๋ณต์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.

 

 

โ–  ์ž๋ฐ”๊ฐ€ ์ œ๊ณตํ•˜๋Š” ์ดํ„ฐ๋ ˆ์ดํ„ฐ : java.util.Iterator

์ดํ„ฐ๋ ˆ์ดํ„ฐ ํŒจํ„ด์„ ์œ„ํ•ด ์ง์ ‘ Iterator ๋ฅผ ์ž‘์„ฑํ•ด๋ดค์ง€๋งŒ, java ์—์„œ ์ œ๊ณตํ•ด์ฃผ๋Š” Iterator ๊ฐ€ ์กด์žฌํ•œ๋‹ค.

1. Menu ์ธํ„ฐํŽ˜์ด์Šค

import java.util.Iterator;

public interface Menu {
    public Iterator createIterator();
}

2. MenuItem ํด๋ž˜์Šค

public class MenuItem {
    String name; // ๋ฉ”๋‰ด๋ช…
    String description; // ์„ค๋ช…
    boolean vegetarian; // ๋ฒ ์ง€ํ…Œ๋ฆฌ์–ธ ์—ฌ๋ถ€
    Long price; // ๊ฐ€๊ฒฉ

    public MenuItem(String name, String description, Boolean vegetarian, Long price) {
        this.name = name;
        this.description = description;
        this.vegetarian = vegetarian;
        this.price = price;
    }
    // getter
    public String getName() { return name; }
    public String getDescription() { return description; }
    public boolean isVegetarian() { return vegetarian; }
    public Long getPrice() { return price; }
}

3. SteakMenu, BurgerMenu ํด๋ž˜์Šค

import java.util.Arrays;
import java.util.Iterator;

/**
 * ์Šคํ…Œ์ดํฌ ๋ฉ”๋‰ด : Array
 */
public class SteakMenu implements Menu {

    public static final int MAX_ITEMS = 5; // ์ตœ๋Œ€ ๋ฉ”๋‰ด ๊ฐฏ์ˆ˜ 5๊ฐœ
    int numberOfItems = 0;
    MenuItem[] menuItemList;

    public SteakMenu() {
        menuItemList = new MenuItem[MAX_ITEMS];
        addMenu("์•ˆ์‹ฌ ์Šคํ…Œ์ดํฌ", "์•ˆ์‹ฌ์Šคํ…Œ์ดํฌ, ๊ตฌ์šด๋ฒ„์„ฏ, ๊ตฌ์šด์–‘ํŒŒ", false, 18000);
        addMenu("T๋ณธ ์Šคํ…Œ์ดํฌ", "T๋ณธ ์Šคํ…Œ์ดํฌ, ๊ตฌ์šดํŒŒ์ธ์• ํ”Œ, ๊ตฌ์šด๋ฒ„์„ฏ", false, 20000);
        addMenu("๋“ฑ์‹ฌ ์Šคํ…Œ์ดํฌ", "๋“ฑ์‹ฌ์Šคํ…Œ์ดํฌ, ๊ตฌ์šด๋งˆ๋Š˜, ๊ตฌ์šด๊ฐ์ž", false, 15000);
        addMenu("์ฑ„๋ ์Šคํ…Œ์ดํฌ", "์ฑ„๋์Šคํ…Œ์ดํฌ, ๊ตฌ์šด๋งˆ๋Š˜, ๊ตฌ์šด์•„์ŠคํŒŒ๋ผ๊ฑฐ์Šค", false, 12000);
        addMenu("์ฝฉ๊ณ ๊ธฐ ์Šคํ…Œ์ดํฌ", "์ฝฉ๊ณ ๊ธฐ์Šคํ…Œ์ดํฌ, ๊ตฌ์šด์•„์ŠคํŒŒ๋ผ๊ฑฐ์Šค, ๊ตฌ์šด์–‘ํŒŒ, ๊ตฌ์šดํŒŒ์ธ์• ํ”Œ", true, 17000);
    }

    public void addMenu(String name, String description, boolean vegetarian, long price) {
        MenuItem menuItem = new MenuItem(name, description, vegetarian, price);

        if (numberOfItems >= MAX_ITEMS) {
            System.err.println("๋“ฑ๋กํ•  ์ˆ˜ ์žˆ๋Š” ๋ฉ”๋‰ด ๊ฐฏ์ˆ˜๋ฅผ ์ดˆ๊ณผํ–ˆ์Šต๋‹ˆ๋‹ค.");
        } else {
            menuItemList[numberOfItems] = menuItem;
            numberOfItems += 1;
        }
    }

    @Override
    public Iterator<MenuItem> createIterator() {
        // ๋ฐฐ์—ด : stream ์‚ฌ์šฉํ•œ Iterator
        return Arrays.stream(menuItemList).iterator();
    }
}

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * ํ–„๋ฒ„๊ฑฐ ๋ฉ”๋‰ด : ArrayList
 */
public class BurgerMenu implements Menu {
    List<MenuItem> menuItemList;

    public BurgerMenu() {
        menuItemList = new ArrayList<>();
        addItem("๋จธ์‰ฌ๋ฃธ๋ฒ„๊ฑฐ", "๋ฒ„์„ฏ, ์ฝฉ์ด ์žฌ๋ฃŒ์ธ ํŒจํ‹ฐ๋กœ ๋งŒ๋“  ๋ฒ„๊ฑฐ", true, 8000);
        addItem("์น˜ํ‚จ๋ฒ„๊ฑฐ", "์น˜ํ‚จ ๋‹ค๋ฆฌ์‚ด๋กœ ๋งŒ๋“  ๋ฒ„๊ฑฐ", false, 9000);
        addItem("ํ•œ์šฐ๋ฒ„๊ฑฐ", "1++ ํ•œ์šฐ๋กœ ๋งŒ๋“  ๋ฒ„๊ฑฐ", false, 15000);
        addItem("์ƒˆ์šฐ๋ฒ„๊ฑฐ", "์ƒˆ์šฐ๊ฐ€ ๋“ฌ๋ฟ ๋“ค์–ด๊ฐ„ ๋ฒ„๊ฑฐ", false, 10000);
        addItem("์•ผ์ฑ„๋ฒ„๊ฑฐ", "์•ผ์ฑ„๋ฅผ ํŠ€๊ฒจ ๋งŒ๋“  ๋ฒ„๊ฑฐ", true, 7000);
    }

    public void addItem(String name, String description, boolean vegetarian, long price) {
        MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
        menuItemList.add(menuItem);
    }

    @Override
    public Iterator<MenuItem> createIterator() {
        // ์ž๋ฐ”๊ฐ€ ์ œ๊ณตํ•ด์ฃผ๋Š” Iterator
        return menuItemList.iterator();
    }
}

4. ํด๋ผ์ด์–ธํŠธ Clerk

import java.util.Iterator;

public class Clerk {

    Menu steakMenu;
    Menu burgerMenu;

    public Clerk(Menu steakMenu, Menu burgerMenu) {
        this.steakMenu = steakMenu;
        this.burgerMenu = burgerMenu;
    }

    /**
     * ์ดํ„ฐ๋ ˆ์ดํ„ฐ ์‚ฌ์šฉ
     */
    public void printMenu() {
        Iterator<MenuItem> steakMenuIterator = steakMenu.createIterator();
        Iterator<MenuItem> burgerMenuIterator = burgerMenu.createIterator();
        System.out.println("===== Steak Menu =====");
        printMenu(steakMenuIterator);
        System.out.println("===== Burger Menu =====");
        printMenu(burgerMenuIterator);
    }

    public void printMenu(Iterator<MenuItem> menuItemIterator) {
        while (menuItemIterator.hasNext()) {
            MenuItem menuItem = menuItemIterator.next();
            System.out.println("name = " + menuItem.getName() + ", price = " + menuItem.getPrice());
            System.out.println("description = " + menuItem.getDescription());
        }
    }

    public void printVegetarianMenu() {
        printVegetarianMenu(steakMenu.createIterator());
        printVegetarianMenu(burgerMenu.createIterator());
    }

    public void printVegetarianMenu(Iterator<MenuItem> iterator) {
        while (iterator.hasNext()) {
            MenuItem menuItem = iterator.next();
            if (menuItem.isVegetarian()) {
                System.out.println("name = " + menuItem.getName() + ", price = " + menuItem.getPrice());
                System.out.println("description = " + menuItem.getDescription());
            }
        }
    }

    public boolean isItemVegetarian(String name) {
        Iterator steakMenuIterator = steakMenu.createIterator();
        Iterator burgerMenuIterator = burgerMenu.createIterator();
        if (isVegetarian(name, steakMenuIterator)) {
            return true;
        }
        if (isVegetarian(name, burgerMenuIterator)) {
            return true;
        }
        return false;
    }

    private boolean isVegetarian(String name, Iterator<MenuItem> menuItemIterator) {
        while (menuItemIterator.hasNext()) {
            MenuItem menuItem = menuItemIterator.next();
            if (menuItem.getName().equals(name)) {
                if (menuItem.isVegetarian()) {
                    return true;
                }
            }
        }
        return false;
    }

}

 

 

 

โ–  UML Diagram

๋ชจ๋“  ํ•ญ๋ชฉ์— ์ผ์ผ์ด ์ ‘๊ทผํ•˜๋Š” ์ž‘์—…์„ ๋ฐ˜๋ณต์ž ๊ฐ์ฒด์—์„œ ๋งก๊ฒŒ ๋œ๋‹ค.  ์ปฌ๋ ‰์…˜ ๊ฐ์ฒด ์•ˆ์— ๋“ค์–ด์žˆ๋Š” ๋ชจ๋“  ํ•ญ๋ชฉ์— ์ ‘๊ทผํ•˜๋Š” ๋ฐฉ์‹์ด ํ†ต์ผ๋œ๋‹ค. ๊ทธ๋กœ์ธํ•ด ์–ด๋–ค ์ข…๋ฅ˜์˜ ์ง‘ํ•ฉ์ฒด์— ๋Œ€ํ•ด์„œ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋‹คํ˜•์ ์ธ ์ฝ”๋“œ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. ๋˜ํ•œ ์ง‘ํ•ฉ์ฒด๋Š” ๋ฐ˜๋ณต์ž‘์—…์— ๋Œ€ํ•ด์„œ ์†์„ ๋–ผ๊ณ  ์ž์‹ ์˜ ์ปฌ๋ ‰์…˜ ๊ด€๋ฆฌ์—๋งŒ ์ „๋…ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

โ–  ๋””์ž์ธ ์›์น™ : ๋‹จ์ผ ์—ญํ•  ์›์น™

๋งŒ์•ฝ, Iterator ๋ฅผ ๋”ฐ๋กœ ๋งŒ๋“ค์ง€ ์•Š๊ณ , ํด๋ž˜์Šค(์˜ˆ์ œ์—์„œ SteakMenu, BurgerMenu์— ํ•ด๋‹น) ์—์„œ ๋ฐ˜๋ณต์ž์šฉ ๋ฉ”์†Œ๋“œ ๊ด€๋ จ๊ธฐ๋Šฅ์„ ์ „๋ถ€ ๊ตฌํ˜„ํ–ˆ๋‹ค๋ฉด ์–ด๋–จ๊นŒ? ๋ฉ”์†Œ๋“œ๊ฐ€ ๊ฝค ๋งŽ์•„์ง€๊ฒŒ๋œ๋‹ค. ๋ฉ”์†Œ๋“œ ์ˆ˜๊ฐ€ ๋งŽ์•„์ง„๋‹ค๋Š” ๊ฒƒ์ด ์ข‹์ง€์•Š์€ ์ด์œ ๊ฐ€ ๋ ๊นŒ?

 

ํด๋ž˜์Šค์—์„œ ์›๋ž˜ ๊ทธ ํด๋ž˜์Šค์˜ ์—ญํ•  (์ง‘ํ•ฉ์ฒด ๊ด€๋ฆฌ) ์™ธ์— ๋‹ค๋ฅธ ์—ญํ•  (๋ฐ˜๋ณต์ž ๋ฉ”์†Œ๋“œ) ์„ ์ฒ˜๋ฆฌํ•˜๋„๋ก ํ•˜๋ฉด ๋‘ ๊ฐ€์ง€ ์ด์œ ๋กœ ์ธํ•ด ๊ทธ ํด๋ž˜์Šค์— ๋ณ€๊ฒฝ์ด ์ƒ๊ธธ ์ˆ˜ ์žˆ๋‹ค.

    (1) ์ปฌ๋ ‰์…˜์ด ์–ด๋–ค ์ด์œ ๋กœ ๋ฐ”๋€Œ๊ฒŒ ๋˜๋ฉด ํ•ด๋‹น ํด๋ž˜์Šค์˜ ๋ณ€๊ฒฝ์ด ์ƒ๊ธด๋‹ค.

    (2) ๋ฐ˜๋ณต์ž ๊ด€๋ จ ๊ธฐ๋Šฅ์ด ๋ฐ”๋€Œ๊ฒŒ ๋˜๋ฉด ํ•ด๋‹น ํด๋ž˜์Šค์˜ ๋ณ€๊ฒฝ์ด ์ƒ๊ธด๋‹ค.

 

๋”ฐ๋ผ์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋””์ž์ธ ์›์น™์ด ์žˆ๋‹ค.

๐Ÿ“Œ ๋””์ž์ธ ์›์น™ : ๋‹จ์ผ ์—ญํ•  ์›์น™
      ํด๋ž˜์Šค๋ฅผ ๋ฐ”๊พธ๋Š” ์ด์œ ๋Š” ํ•œ ๊ฐ€์ง€ ๋ฟ์ด์–ด์•ผ ํ•œ๋‹ค.

ํด๋ž˜์Šค๋ฅผ ๊ณ ์น˜๋Š” ๊ฒƒ์€ ์ตœ๋Œ€ํ•œ ํ”ผํ•ด์•ผ ํ•œ๋‹ค. ๋ณ€๊ฒฝ์€ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์ˆ˜๋งŽ์€ ๋ฌธ์ œ๋ฅผ ์•ผ๊ธฐํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

ํ•œ ์—ญํ• ์€ ํ•œ ํด๋ž˜์Šค์—์„œ๋งŒ ๋งก๋„๋ก ํ•ด์•ผํ•œ๋‹ค.

 

๐Ÿ“Œ ์‘์ง‘๋„ (cohesion)
ํ•œ ํด๋ž˜์Šค ๋˜๋Š” ๋ชจ๋“ˆ์ด ํŠน์ • ๋ชฉ์  ๋˜๋Š” ์—ญํ• ์„ ์–ผ๋งˆ๋‚˜ ์ผ๊ด€๋˜๊ฒŒ ์ง€์›ํ•˜๋Š”์ง€๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ์ฒ™๋„์ด๋‹ค.

์–ด๋–ค ๋ชจ๋“ˆ ๋˜๋Š” ํด๋ž˜์Šค์˜ ์‘์ง‘๋„๊ฐ€ ๋†’๋‹ค๋Š” ๊ฒƒ์€ ์ผ๋ จ์˜ ์„œ๋กœ ์—ฐ๊ด€๋œ ๊ธฐ๋Šฅ์ด ๋ฌถ์—ฌ์žˆ๋‹ค๋Š” ๊ฒƒ์„, ์‘์ง‘๋„๊ฐ€ ๋‚ฎ๋‹ค๋Š” ๊ฒƒ์€ ์„œ๋กœ ์ƒ๊ด€ ์—†๋Š” ๊ธฐ๋Šฅ๋“ค์ด ๋ฌถ์—ฌ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๋œปํ•œ๋‹ค.

์‘์ง‘๋„๋Š” ๋‹จ์ผ ์—ญํ•  ์›์น™์—์„œ๋งŒ ์“ฐ์ด๋Š” ์šฉ์–ด๋Š” ์•„๋‹ˆ๊ณ , ์ข€๋” ๊ด€๋ฒ”์œ„ํ•œ ์šฉ๋„๋กœ ์“ฐ์ด๋Š” ์šฉ์–ด์ด๋‹ค. ํ•˜์ง€๋งŒ ๊ทธ ๋‘˜์€ ์„œ๋กœ ๋ฐ€์ ‘ํ•˜๊ฒŒ ์—ฐ๊ด€๋˜์–ด ์žˆ๋‹ค. ์ด ์›์น™์„ ์ž˜ ๋”ฐ๋ฅด๋Š” ํด๋ž˜์Šค๋Š” ๋‘ ๊ฐœ ์ด์ƒ์˜ ์—ญํ• ์„ ๋งก๊ณ  ์žˆ๋Š” ํด๋ž˜์Šค์— ๋น„ํ•ด ์‘์ง‘๋„๊ฐ€ ๋†’๊ณ , ๊ด€๋ฆฌํ•˜๊ธฐ๋„ ๋” ์šฉ์ดํ•œ ํŽธ์ด๋‹ค.

 


์ฐธ๊ณ 
ํ—ค๋“œ ํผ์ŠคํŠธ ๋””์ž์ธ ํŒจํ„ด (Head First Design Patterns) - ์—๋ฆญ ํ”„๋ฆฌ๋จผ,์—˜๋ฆฌ์ž๋ฒ ์Šค ๋กญ์Šจ,์ผ€์ด์‹œ ์‹œ์—๋ผ,๋ฒ„ํŠธ ๋ฒ ์ด์ธ 

๋ฐ˜์‘ํ˜•