-
[Design Pattern] Iteration PatternLearn/Architecture 2022. 8. 28. 14:41
# 개요
- 비슷한 기능을 하는 코드인데 자료구조가 달라서 동일한 방식으로 핸들링이 안되는 경우가 있음
- 자료구조를 노출하지 않으면서 aggregate object의 element에 접근할 수 있도록 하기 위한 패턴
※aggregate object: 하나의 오브젝트 안에 다른 오브젝트가 포함된 것. (container 혹은 collection라고 불림)
예시
아래와 같이 MenuItem을 정의했을 때
public class MenuItem { String name; String description; boolean vegetarian; double price; public MenuItem (String name, String description, boolean vegetarian, double price ) { // code here } // set of getter methods to get access to the fields. }
아래와 같이 어딘가에서는 ArrayList를 쓰고 또 다른 곳에서는 Array를 쓸 수 있다.
public class PancakeHouseMenu { ArrayList menuItems; ... public ArrayList getMenuItems() { return menuItems; } ... } ... public class DinerMenu { MenuItem[] menuItems; ... public MenuItem[] getMenuItems() { return menuItems; } ... }
문제는 사용자 입장에서는 ArrayList는 get함수로 꺼내야하고 Array는 [i]와 같이 인덱스로 접근한다.
# Iterator Pattern
- 클라이언트 입장에서는 자료구조에는 관심이 없다.
- 다음 꺼낼 것이 있는지 확인(hasNext)하고 꺼낼 수 있으면(next) 된다.
- 하위 클래스에서 Iterator를 구현해주면 된다.
예시
public interface Iterator { boolean hasNext(); Object next(); } 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) return false; else return true; } }
위와 같이 Iterator를 구현하고 아래와 같이 클라이언트에게 함수를 제공해주면 된다.
public class DinerMenu { // constructor // addItem MenuItem[] menuItems; /* public menuItem[] getMenuItems() { return menuItems; } */ public Iterator createIterator() { return new DinerMenuIterator(menuItems); } }
클라이언트는 아래와 같이 쓸 수 있다.
public class Waitress { ... public void printMenu() { // Iterator 생성 Iterator pancakeIterator = pancakeHouseMenu.createIterator(); Iterator dinerIterator = dinerMenu.createIterator(); ... // 위에서 생성한 Iterator와 함께 아래 overloading된 함수를 호출한다. printMenu(dinerIterator); } private void printMenu(Iterator iterator) { // hasNext로 확인하고 next로 꺼낸다. while (iterator.hasNext()) { MenuItem menuItem = (MenuItem) iterator.next(); System.out.println(menuItem.getName() + ", "); .. } } }
Iterator Pattern을 클래스 다이어그램으로 표현하면 다음과 같다.
createIterator를 Interface에서 한번에 해주면 클라이언트가 Iterator를 사용하기 더 편하다.
이렇게 구현하면 Aggregator와 Iterator로 책임이 분리되어 SRP관점에서도 좋다.
# Java's Iterator
위의 예시에서는 Iterator도 구현을 했는데, 자바에서 제공하는걸 쓰면 더 간편하다.
next, hasNext는 위와 같고 remove를 추가로 구현해야한다.
자바에서 Collection에 해당하는 객체들은 iterator함수를 쓰면 Iterator를 얻을 수 있다.
'Learn > Architecture' 카테고리의 다른 글
[Design Pattern] Mediator Pattern (0) 2022.08.29 [Design Pattern] State Pattern (0) 2022.08.29 [Design Pattern] Template Method Pattern (0) 2022.08.28 [Design Pattern] Observer Pattern (0) 2022.08.27 [Design Pattern] Strategy Pattern (0) 2022.08.26