본문 바로가기

PROGRAMMING/Design Pattern

[GoF] 반복자 (Iterator) 패턴

반복자 (Iterator) 패턴 행동 패턴

컨테이너를 가로지르는 객체를 통해 컨테이너의 요소들을 순회할 수 있도록 해 줍니다.


일련의 데이터 집합을 저장하기 위해 사용되는 컨테이너는 크게 두가지 용도로 사용되어진다. 첫 번째는 컨테이너의 특정 요소를 검색하는 것이고, 두 번째는 컨테이너 안의 모든 요소를 순회하는 것이다. 이 순회의 방법으로는 컨테이너의 종류에 따라 다양하다.

예를 들어, 일반적인 배열의 모든 요소를 순회하려 한다면 색인을 위한 정수를 하나 선언하고 반복문을 통해 값을 늘려가며 배열의 끝까지 차례대로 접근할 수 있고, 연결 리스트의 모든 요소를 순회하려 한다면 첫번째 노드에 접근하여 그 노드가 참조하는 다음 노드를 계속 접근해서 마지막 노드까지 접근하는 것으로 연결 리스트의 모든 요소를 접근할 수 있다.

이런 방법들은 컨테이너에 대한 순회를 명료하게 수행할 수 있으나, 다만 불편한 점은 클라이언트가 컨테이너의 모든 요소를 순회하는 것에 대한 알고리즘을 직접 구현해야 한다는 것이다. 클라이언트는 컨테이너의 구조를 파악할 필요 없이 일반화된 요소의 순회를 원한다. 이를 구현할 수 있게 해 주는 것이 GoF 디자인 패턴에서 제시하는 반복자 패턴이다.

반복자 (Iterator) 패턴은 컨테이너에 대해 순회할 수 있는 객체를 정의하고 이를 통해 컨테이너의 모든 요소를 순회할 수 있게 하는 패턴이다. 클라이언트는 요소의 순회에 대한 알고리즘을 직접 구현하는 대신에 해당 컨테이너가 제공하는 반복자 객체의 인터페이스를 통해 어떤 컨테이너에 대해서라도 동일한 방법으로 간편하게 요소를 순회할 수가 있다.

반복자 패턴을 사용하면 요소의 순회에 대한 알고리즘을 컨테이너로부터 분리시켜 확장성이 용이해지고, 컨테이너의 직접적인 노출 없이 반복자 객체를 통해 요소에 대한 순회를 수행할 수 있게 해 준다. 또한 하나의 컨테이너에 여러 반복자 객체를 구현함으로써 컨테이너에 대한 다양한 순회 방법을 제공할 수 있다.

C# 에서는 컨테이너에 대한 순회 방법을 추상화한 IEnumeratorIEnumerable 인터페이스를 제공하고 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
public class PatternIterator
{
    public interface IAggregate
    {
        IIterator CreateIterator();
    }
 
    public class Aggregate : IAggregate
    {
        private string[] _strings;
 
        public string[] strings
        {
            get
            { return _strings; }
        }
 
        public Aggregate(string[] strings)
        {
            _strings = strings;
        }
 
        public IIterator CreateIterator()
        {
            return new Iterator(this);
        }
    }
 
    public interface IIterator
    {
        string Next();
        bool HasNext();
    }
 
    public class Iterator : IIterator
    {
        private Aggregate _aggregate;
 
        private int _index;
 
        public Iterator(Aggregate aggregate)
        {
            _aggregate = aggregate;
 
            _index = 0;
        }
 
        public string Next()
        {
            return _aggregate.strings[_index++];
        }
 
        public bool HasNext()
        {
            return _index < _aggregate.strings.Length;
        }
    }
 
    public static void Main(string[] args)
    {
        string[] strings = new string[]
        {
            "string A",
            "string B",
            "string C",
            "string D",
            "string E"
        };
 
        IAggregate aggregate = new Aggregate(strings);
 
        IIterator iterator = aggregate.CreateIterator();
 
        while (iterator.HasNext())
        {
            Console.WriteLine(iterator.Next());
        }
    }
}
cs

1
2
3
4
5
6
string A
string B
string C
string D
string E
Press any key to continue . . .
cs

위의 예제에서 클라이언트는 생성한 Aggregate 객체에서 제공받은 Iterator 객체를 통해 Aggregate 객체의 모든 요소를 순회하고 있다. while 문에서 Iterate 객체의 HasNext() 메소드가 false를 반환할 때 까지 Next() 메소드를 통해 Aggregate 객체의 다음 요소를 반복해서 가져오고 있다.