본문 바로가기

JAVA/디자인 패턴

[Design Pattern] Iterator(반복자) 패턴이란?

반응형
행위 패턴(Behavioral Pattern)


반복자 패턴(Iterator Pattern)은 컬렉션(Collection) 객체의 요소(element)에 접근하는 방법을 제공하는 패턴입니다. 이 패턴은 컬렉션 객체와 반복자 객체(Iterator)를 분리하여 구현합니다. 컬렉션 객체는 요소를 추가하고 제거하는 책임을 가지고, 반복자 객체는 컬렉션 객체 내의 요소를 하나씩 가져오는 책임을 가집니다.

반복자 패턴을 구현하면, 컬렉션 객체의 구현과 사용자 코드를 분리하여 코드의 재사용성과 유지보수성을 높일 수 있습니다. 또한, 컬렉션 객체 내부 구현을 외부에 노출하지 않으므로 객체의 불변성(Immutability)을 유지할 수 있습니다.

반복자 패턴은 다음과 같이 구성됩니다.

 

  1. Iterator 인터페이스: 반복자 객체가 가져야 할 메서드를 선언하는 인터페이스입니다. 일반적으로 hasNext()와 next() 메서드가 선언됩니다.
  2. ConcreteIterator 클래스: Iterator 인터페이스를 구현하여 반복자 객체를 생성합니다. 컬렉션 객체의 요소에 접근하는 책임을 가집니다.
  3. Aggregate 인터페이스: 컬렉션 객체가 가져야 할 메서드를 선언하는 인터페이스입니다. 일반적으로 createIterator() 메서드가 선언됩니다.
  4. ConcreteAggregate 클래스: Aggregate 인터페이스를 구현하여 컬렉션 객체를 생성합니다. 컬렉션 객체에 요소를 추가하고 제거하는 책임을 가집니다.

예를 들어, 자바에서는 java.util.Iterator 인터페이스와 java.util.Collection 인터페이스가 이 패턴을 구현하는데 사용됩니다. Iterator 인터페이스는 hasNext()와 next() 메서드를 선언하고, Collection 인터페이스는 createIterator() 메서드를 선언합니다. 실제로 이 인터페이스들을 구현하는 클래스는 ArrayList, LinkedList, HashSet 등의 컬렉션 클래스입니다.

아래는 자바에서 Iterator 패턴을 사용한 예제 코드입니다.

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

public class IteratorPatternExample {
    public static void main(String[] args) {
        // create a collection of integers
        ArrayList<Integer> numbers = new ArrayList<Integer>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);

        // create an iterator for the collection
        Iterator<Integer> iterator = numbers.iterator();

        // use the iterator to access the collection elements
        while (iterator.hasNext()) {
            Integer number = iterator.next();
            System.out.println(number);
        }
    }
}



위 코드에서 ArrayList는 ConcreteAggregate 클래스에 해당하고, iterator() 메서드는 Iterator 인터페이스를 구현한 ConcreteIterator 클래스의 인스턴스입니다. while 루프에서 hasNext() 메서드를 호출하여 컬렉션의 다음 요소가 있는지 확인한 후, next() 메서드를 호출하여 현재 요소를 가져옵니다. 이것이 Iterator 패턴의 핵심 아이디어입니다.

반복자 패턴은 컬렉션의 요소에 접근하는 방법을 일반화하여 여러 종류의 컬렉션 객체를 쉽게 반복할 수 있도록 합니다. 또한, 컬렉션 객체와 반복자 객체를 분리하여, 컬렉션 객체의 내부 구현이 변경되더라도 외부에서 영향을 받지 않도록 합니다. 이는 객체지향 설계 원칙 중 하나인 개방-폐쇄 원칙(Open-Closed Principle)을 준수하는 디자인 패턴입니다.

 

 

Iterator 패턴 예제

Diagrams

 

자바에서 반복자 패턴을 구현하기 위해서는 Iterator 인터페이스와 ConcreteIterator 클래스, Aggregate 인터페이스와 ConcreteAggregate 클래스를 만들어야 합니다. 이를 위해서는 먼저 컬렉션 객체가 되는 클래스를 만들고, 이를 Aggregate 인터페이스를 구현하여 ConcreteAggregate 클래스를 만듭니다. 그리고 Iterator 인터페이스를 구현하여 ConcreteIterator 클래스를 만들어서, 컬렉션 객체의 요소에 접근하도록 합니다.

아래는 ArrayList를 컬렉션 객체로 사용한 반복자 패턴 예제 코드입니다.

import java.util.ArrayList;

// Aggregate interface
interface Aggregate<T> {
    Iterator<T> createIterator();
}

// Concrete Aggregate class
class MyArrayList<T> implements Aggregate<T> {
    private ArrayList<T> list;

    public MyArrayList() {
        list = new ArrayList<T>();
    }

    public void add(T item) {
        list.add(item);
    }

    public T get(int index) {
        return list.get(index);
    }

    public int size() {
        return list.size();
    }

    @Override
    public Iterator<T> createIterator() {
        return new MyArrayListIterator<T>(this);
    }
}

// Iterator interface
interface Iterator<T> {
    boolean hasNext();
    T next();
}

// Concrete Iterator class
class MyArrayListIterator<T> implements Iterator<T> {
    private MyArrayList<T> myArrayList;
    private int index;

    public MyArrayListIterator(MyArrayList<T> myArrayList) {
        this.myArrayList = myArrayList;
        this.index = 0;
    }

    @Override
    public boolean hasNext() {
        return index < myArrayList.size();
    }

    @Override
    public T next() {
        T item = myArrayList.get(index);
        index++;
        return item;
    }
}

// Client code
public class Main {
    public static void main(String[] args) {
        MyArrayList<String> myArrayList = new MyArrayList<>();
        myArrayList.add("apple");
        myArrayList.add("banana");
        myArrayList.add("orange");

        Iterator<String> iterator = myArrayList.createIterator();
        while (iterator.hasNext()) {
            String item = iterator.next();
            System.out.println(item);
        }
    }
}


위 코드에서 MyArrayList 클래스는 ConcreteAggregate 클래스로, ArrayList를 내부적으로 사용하여 요소를 저장하고, createIterator() 메서드를 구현하여 MyArrayListIterator 클래스의 인스턴스를 생성합니다. MyArrayListIterator 클래스는 Iterator 인터페이스를 구현하여, MyArrayList 클래스의 요소에 접근합니다.

클라이언트 코드에서는 MyArrayList 클래스를 생성하고, add() 메서드를 사용하여 요소를 추가합니다. 그리고 createIterator() 메서드를 호출하여 Iterator 객체를 가져와서, hasNext() 메서드와 next() 메서드를 사용하여 요소를 반복하면서 출력합니다.

 

이처럼 반복자 패턴을 사용하면 서로 다른 컬렉션 클래스들도 일관된 인터페이스를 제공할 수 있습니다. 이를 통해 클라이언트 코드에서는 모든 컬렉션 객체에 대해 동일한 인터페이스를 사용할 수 있습니다.

반응형