ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Design Pattern] Iteration Pattern
    Learn/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

    댓글

Designed by Tistory.