이터레이터 패턴(Iterator pattern)은 가장 간단하면서도, 자주 사용되는 디자인 패턴 중 하나다. 이 패턴은 컬렉션이나 집합 객체의 내부적인 구현 방법을 드러내지 않으면서도 그 안에 있는 모든 원소에 순차적으로 접근할 수 있는 수단을 제공한다.

 

이터레이터 패턴의 UML 클래스 다이어그램

  • Iterator: 원소를 접근하고 순회하는 데 필요한 인터페이스를 제공한다. (다음 요소를 가져오거나, 현재의 위치를 찾거나, 다시 반복을 시작하는 등의 연산)
  • ConcreteIterator: Iterator에 정의된 인터페이스를 구현하는 클래스. 순회 과정 중 집합 객체 내에서 현재 위치를 기억한다.
  • IterableCollection: Iterator 객체를 생성하는 인터페이스를 정의한다.
  • ConcreteCollection: 해당하는 ConcreteIterator의 인스턴스를 반환하는 Iterator 생성 인터페이스를 구현한다.

 

장점

  • 구조가 복잡한 집합 객체 내에서 어떤 식으로 일이 처리되는지에 대해서 전혀 모르는 상태에서 그 안에 있는 들어있는 모든 항목들에 대해 반복 작업을 수행할 수 있다.
  • 컬렉션 객체 내에 들어있는 모든 항목에 접근하는 방식이 통일되어 있으므로 어떤 종류의 집합체에 대해서도 사용할 수 있는 다형적인 코드를 만들 수 있다.
  • 모든 항목에 일일이 접근하는 작업을 컬렉션 객체가 아닌 이터레이터 객체에서 맡게 된다. 이렇게 하면, 집합체의 인터페이스 및 구현이 간단해질 뿐만 아니라, 집합체에서는 반복 작업에서 손을 떼고 원래 자신이 할 일에만 전념할 수 있다.

 

예제 코드

// Iterator: https://refactoring.guru/design-patterns/iterator
using System;
using System.Collections;
using System.Collections.Generic;

namespace RefactoringGuru.DesignPatterns.Iterator.Conceptual
{
    abstract class Iterator : IEnumerator
    {
        object IEnumerator.Current => Current();

        public abstract int Key();

        public abstract object Current();

        public abstract bool MoveNext();

        public abstract void Reset();
    }

    abstract class IteratorAggregate : IEnumerable
    {
        public abstract IEnumerator GetEnumerator();
    }

    class AlphabeticalOrderIterator : Iterator
    {
        private WordsCollection _collection;

        private int _position = -1;

        private bool _reverse = false;

        public AlphabeticalOrderIterator(WordsCollection collection, bool reverse = false)
        {
            this._collection = collection;
            this._reverse = reverse;

            if (reverse)
            {
                this._position = collection.getItems().Count;
            }
        }

        public override object Current()
        {
            return this._collection.getItems()[_position];
        }

        public override int Key()
        {
            return this._position;
        }

        public override bool MoveNext()
        {
            int updatedPosition = this._position + (this._reverse ? -1 : 1);

            if (updatedPosition >= 0 && updatedPosition < this._collection.getItems().Count)
            {
                this._position = updatedPosition;
                return true;
            }
            else
            {
                return false;
            }
        }

        public override void Reset()
        {
            this._position = this._reverse ? this._collection.getItems().Count - 1 : 0;
        }
    }

    class WordsCollection : IteratorAggregate
    {
        List<string> _collection = new List<string>();

        bool _direction = false;

        public void ReverseDirection()
        {
            _direction = !_direction;
        }

        public List<string> getItems()
        {
            return _collection;
        }

        public void AddItem(string item)
        {
            this._collection.Add(item);
        }

        public override IEnumerator GetEnumerator()
        {
            return new AlphabeticalOrderIterator(this, _direction);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var collection = new WordsCollection();
            collection.AddItem("하나");
            collection.AddItem("둘");
            collection.AddItem("셋");

            Console.WriteLine("정방향 순회:");

            foreach (var element in collection)
            {
                Console.WriteLine(element);
            }

            Console.WriteLine("\n역방향 순회:");

            collection.ReverseDirection();

            foreach (var element in collection)
            {
                Console.WriteLine(element);
            }
        }
    }
}

'프로그래밍 관련 > 객체 지향 설계' 카테고리의 다른 글

정리. SOLID 원칙  (0) 2022.01.21
메모. Command pattern  (0) 2019.11.26
메모. Proxy pattern  (0) 2019.11.18
메모. Facade pattern  (0) 2019.11.17
메모. Factory method pattern  (0) 2019.05.19