반복자(Iterator) 패턴

차동준·2022년 7월 25일
0

CS-디자인패턴

목록 보기
12/16
post-thumbnail

👨‍💻반복자(Iterator) 패턴이란?


컬렉션의 구현 방법을 노출하지 않은 채
집합체(aggregate) 내의 모든 항목에 접근하는 방법을 제공하는 디자인 패턴


자료구조(컬렉션, 집합체)에 접근하는 기능들을 분리시켜서 캡슐화 한다.


int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

for (int i = 0; i < arr.length; i++) {
	System.out.println(arr[i]);
}

위 예시에서 집합체에 접근하기 위해 사용된 i 를 추상화하여 구현한 것이 바로 반복자 패턴의 핵심이다.



예시) 메뉴, 집합체, 메뉴테이블반복자, 메뉴테이블


public class Menu {
	private String name;
    
    public Menu(String name) {
    	this.name = name;
    }
    
    public String getName() {
    	return this.name;
    }
}

이름 멤버를 가지고 있는 메뉴 클래스를 예시로 들어보면,

public interface Aggregate {
	public Iterator createIterator();
}

반복자를 생성해야 하는 집합체 인터페이스를 생성해주고,

public class MenuTableIterator implements Iterator<Menu> {
	private MenuTable menuTable;
    priavet int index = 0;
    
    public MenuTableIterator(MenuTable menuTable) {
    	this.menuTable = menuTable;
    }
    
    @Override
    public boolean hasNext() {
    	return index < menuTable.getLength();
    }
    
    @Override
    public Menu next() {
    	return MenuTable.getMenu(this.index++);
    }
}

메뉴테이블반복자 클래스를 구현해준다. 이때, 자바의 Iterator 인터페이스를 구현하는데
해당 내용에 대해서는 아래에서 추가 설명하도록 하겠다.
Iterator의 구현 메소드를 재정의해주고,

public class MenuTable implements Aggregate {
	private Menu[] menus;
    private menuIndex = 0;
    
    public MenuTable(int size) {
    	this.menus = new Menu[size];
    }
    
    public getMenu(int index) {
    	return this.menus[index];
    }
    
    public void addMenu(Menu menu) {
    	if (this.index < this.menus.length) {
        	this.menus[menuIndex++] = menu;
        } else {
        	System.out.println("메뉴판이 꽉찼습니다!");
        }
    }
    
    @Override
    public Iterator createIterator() {
    	return new MenuTableIterator(this);
    }
}

메뉴테이블이 집합체(Aggregate) 인터페이스를 구현하여
반복자를 생성하는 함수를 재정의해준다.
이렇게 반복자클래슬르 구현하게 되면 메뉴테이블의 menus 배열에 접근하는 방법을 추상화시켜서 사용할 수 있다.

public static void main(String[] args) {
	MenuTable menuTable = new MenuTable(5);
    
    Menu menu1 = new Menu("김치볶음밥");
    Menu menu2 = new Menu("제육볶음");
    Menu menu3 = new Menu("마라탕");
    Menu menu4 = new Menu("샤브샤브");
    Menu menu5 = new Menu("김치찌개");
    
    menuTable.addMenu(menu1);
    menuTable.addMenu(menu2);
    menuTable.addMenu(menu3);
    menuTable.addMenu(menu4);
    menuTable.addMenu(menu5);
    
    // 반복자를 이용하여 접근
    Iterator it = MenuTable.createIterator();
    
    while (it.hasNext()) {
    	Menu menu = (Menu) it.next();
        System.out.println(menu.getName();
    }
    
    // 김치볶음밥
    // 제육볶음
    // 마라탕
    // 샤브샤브
    // 김치찌개
}

이렇게 하면 MenuTable 클래스에 의존하지 않고 MenuTable의 menus의 모든 요소들에 접근할 수 있게 된다.

반복자 패턴에 대해서 정리하자면,
반복자 인터페이스와 이를 구현한 구체적 반복자를 생성하고
집합체 인터페이스에서 이 반복자를 생성하는 메소드를 구현하게 하고,
해당 집합체 인터페이스를 구현한 구체적인 집합체에서 반복자를 생성하고 해당 반복자를 통해서 구체적 집합체의 모든 요소에 접근할 수 있게 만드는 것이 반복자 패턴이다.

Iterator(반복자): Iterator 인터페이스
ConcreteIterator(구체적 반복자): 메뉴테이블반복자

Aggregate(집합체): Aggregate 인터페이스(반복자 생성 기능을 구현하게 만드는 인터페이스)
Concrete Aggregate(구체적 집합체): 메뉴테이블



🔎반복자 패턴의 장단점


장점

  1. 집합체 클래스의 응집도를 높여준다.
  2. 집합체 내의 구현 과정을 숨기면서 안에 있는 모든 항목에 접근이 가능하게 한다.
  3. 집합체에서 항목에 접근하는 기능을 분리할 수 있다.
  4. 다양한 순회 방법을 만들 수 있다.

단점

  1. 복잡도가 증가할 수 있다.
  2. 사용자가 직접 반복자를 삭제하는 책임을 가져야 한다.
    (힙, 메모리를 삭제하지 않아 오류가 발생할 수 있다.)
  3. 캡슐화 전략을 위배할 가능성이 있어 구현을 신중하게 해야 한다.



👨‍💻 자바의 Iterator 인터페이스


JAVA8등장부터 인터페이스에서 default 메소드를 통해 메소드를 구현할 수 있다.
자바의 Iterator 인터페이스는 hasNext()와 next()함수를 반드시 재정의해서 사용해야 하지만 default로 정의된 remove와 forEachRemaining 등은 반드시 구현할 필요는 없다.

👨‍💻 자바의 Iterable 인터페이스


마찬가지로, Iterable 인터페이스를 잘 보면 반복자를 생성하는 함수를 구현해야 한다.(iterator())

이처럼 자바에서는 Iterator, Iterable 인터페이스를 이용하여 반복자 패턴을 구현할 수 있다.
Iterator 인터페이스는 모든 항목에 접근하는 용도
Iterable 인터페이스는 모든 요소를 가지고 추가적인 메소드를 구현하기 위해서 사용한다.

profile
백엔드를 사랑하는 초보 개발자

0개의 댓글