Iterator Pattern

YeJI Kang·2021년 6월 13일
0

Head First Design Pattern

목록 보기
10/14

이터레이터 패턴(Iterator Pattern)은 언제 필요할까?

code reference

두 개의 구성 객체에서 하나는 정보를 ArrayList 데이터 타입로 가지고 있고 하나는 정보를 Array 데이터 타입으로 가지고 있을 경우, 아래와 같이 각각 다른 loop 를 통해 탐색을 해야합니다.

  • ArrayList - size() 함수 이용
  • Array - 배열에 들어있는 원소의 크기 변수 이용

Waitress.java

public void printMenu() {
        ArrayList breakfastItems = pancakeHouseMenu.getMenuItems();
        for (int i = 0; i < breakfastItems.size(); i++) {
            MenuItem menuItem = (MenuItem) breakfastItems.get(i);
            System.out.print(menuItem.getName() + " ");
            System.out.println(menuItem.getPrice() + " ");
            System.out.println(menuItem.getDescription());
        }

        MenuItem[] lunchItems = dinerMenu.getMenuItems();
        for (int i = 0; i < dinerMenu.numberOfItems; i++) {
            MenuItem menuItem = lunchItems[i];
            System.out.print(menuItem.getName() + " ");
            System.out.println(menuItem.getPrice() + " ");
            System.out.println(menuItem.getDescription());
        }
    }

HashMap 형태의 다른 데이터 타입이 또 추가된다면 loop 를 돌기 위해 또다른 방식의 처리를 해줘야 합니다.

매번 다른 형태의 데이터타입을 가지고 있는 객체에 대해서 위처럼 처리를 해주는 것을 개선하기 위해 반복을 캡슐화한 이터레이터 패턴(Iterator Pattern)을 적용합니다.

이터레이터 패턴(Iterator Pattern) 예제

code reference

각각의 구성 객체(PancakeHouseMenu, DinerMenu)에 Iterator 를 구현한 객체를 하나씩 구성하도록 개선하였습니다. 그럼 아래와 같이 loop 를 도는 부분을 캡슐화하여 통일감 있게 코드를 작성할 수 있습니다.

Waitress.java

	public void printMenu() {
      Iterator pancakeIterator = pancakeHouseMenu.createItertor();
      Iterator dinerIterator = dinerMenu.createIterator();
      printMenu(pancakeIterator);
      printMenu(dinerIterator);
  }

  public void printMenu(Iterator iterator) {
      while(iterator.hasNext()) {
          MenuItem menuItem = (MenuItem) iterator.next();
          System.out.print(menuItem.getName() + " ");
          System.out.println(menuItem.getPrice() + " ");
          System.out.println(menuItem.getDescription());
	}

이렇게 개선하면, 각 객체가 어떤 타입의 데이터(ArrayList, Array, HashMap 등)를 가지고 있는지 Waitress 에서 알 필요 없도록 캡슐화하고, Waitress 에서는 Iterator 객체만 알고 있으면 됩니다.

java.util.Iterator 적용하기

code reference

ArrayListHashMap 의 경우, Java의 Iterator 를 포함하고 있습니다. 따라서 이전의 reference code 에서 PancakeIterator 를 구현할 필요가 없이 아래와 같이 수정할 수 있습니다.

PancakeHouseMenu.java

// Java Iterator 적용 전
public Iterator createItertor() {
        return new PancakeIterator(menuItems);
    }

// Java Iterator 적용 후
public Iterator createItertor() {
        return menuItems.iterator();
    }

Array 의 경우에는 포함하고 있지 않기 때문에 이를 구현해줘야 합니다.

주의 사항

다중 스레드를 사용하는 환경에서는 같은 객체 컬렉션(Collection)에 대해 여러 반복자가 있는 경우, remove() 함수에 대한 처리가 정의되어 있지 않습니다. 따라서 컬렉션에 동시에 접근하는 멀티스레드 코드를 디자인할 때는 매우 조심해야 합니다.

이터레이터 패턴(Iterator Pattern)의 정의

이터레이터 패턴(Iterator Pattern)은 컬렉션 구현 방법을 노출시키지 않으면서도 그 집합체 안에 들어있는 모든 항목에 접근할 수 있게 해주는 방법을 제공해줍니다.

이터레이터 패턴(Iterator Pattern)을 사용하면 좋은 점

  1. 모든 항목에 접근하는 방식이 통일되어 있으면 어떤 종류의 집합체에 대해서도 사용할 수 있는 다형적인 코드를 만들 수 있습니다.
  2. 모든 항목에 일일이 접근하는 작업을 반복자 객체에서 맡게 되기 때문에 집합체의 인터페이스 및 구현이 간단해질 뿐 아니라, 집합체에서는 반복작업에서 손을 떼고 원래 자신이 할 일 (객체 컬렉션 관리)에만 전념할 수 있습니다.

단일 책임의 원칙

클래스에서 맡고 있는 역할들은 나중에 코드 변화를 불러올 수 있습니다.

Design Principal 9.
클래스를 바꾸는 이유는 한 가지 뿐이어야 한다.

클래스를 고치는 것은 최대한 피해야 합니다. 코드를 변경하다 보면 온갖 문제가 발생할 수 있기 대문입니다. 따라서 변화를 최소화하기 위해 한 클래스에서는 응집도 높은 메소드만 담당하고 있는 것이 좋습니다.

profile
재밌는 것만 하고 싶어 ʕ•ﻌ•ʔ

0개의 댓글