1. Iterator Pattern이란 무엇인가

Iterator pattern은 집합 객체의 내부 표현을 노출시키지 않고 집합 객체의 요소를 순회하는 균일한 방법을 제공하는 행위 디자인 패턴입니다.

2. Iterator Pattern의 특징과 장점

Iterator pattern의 특징과 장점은 다음과 같습니다:

  • 컬렉션 객체의 내부 구조를 숨길 수 있으며, 순회 알고리즘을 컬렉션 객체와 독립적으로 만듭니다.
  • 서로 다른 종류의 컬렉션 객체를 순회하는 표준화된 방법을 제공합니다.
  • 클라이언트 코드를 간결하고 명확하게 만듭니다.
  • 다양한 순회 요구에 적응하기 위해 다른 반복자 구현을 제공할 수 있습니다.

3. Iterator Pattern의 실용적인 응용 예

Iterator pattern은 데이터베이스 쿼리 결과 세트를 순회하거나 파일 시스템의 파일 및 폴더를 순회하며, 컬렉션의 요소를 순회하는 등 다양한 실용적인 응용이 있습니다.

4. Golang에서 Iterator Pattern의 구현

4.1 UML 클래스 다이어그램

Iterator Pattern in Golang

4.2 예제 소개

위의 UML 클래스 다이어그램에서 Iterator와 Collection 두 가지 주요 역할이 있습니다.

  • Iterator는 컬렉션 객체를 순회하는 인터페이스를 정의하며, HasNext() 메서드로 다음 요소의 존재 여부를 확인하고 Next() 메서드로 다음 요소를 가져옵니다.
  • ConcreteIterator는 Iterator의 구체적인 구현 클래스로, HasNext()Next() 메서드를 구현합니다.
  • Collection은 반복자 객체를 생성하는 인터페이스를 정의하며, CreateIterator() 메서드를 포함합니다.
  • ConcreteCollection은 Collection의 구체적인 구현 클래스로, CreateIterator() 메서드를 구현합니다.

4.3 구현 단계

이제 Golang에서 Iterator 패턴을 단계별로 구현해 보겠습니다.

4.3.1 Iterator 인터페이스와 Concrete Iterator 클래스 정의

type Iterator interface {
    HasNext() bool
    Next() interface{}
}

type ConcreteIterator struct {
    collection *ConcreteCollection
    index      int
}

func (it *ConcreteIterator) HasNext() bool {
    if it.index < len(it.collection.items) {
        return true
    }
    return false
}

func (it *ConcreteIterator) Next() interface{} {
    if it.HasNext() {
        item := it.collection.items[it.index]
        it.index++
        return item
    }
    return nil
}

4.3.2 Iterable 객체 인터페이스와 Concrete Iterable 객체 클래스 정의

type Collection interface {
    CreateIterator() Iterator
}

type ConcreteCollection struct {
    items []interface{}
}

func (c *ConcreteCollection) CreateIterator() Iterator {
    return &ConcreteIterator{
        collection: c,
        index:      0,
    }
}

4.3.3 Iterable 객체 클래스에서 Iterator 생성 로직 구현

func main() {
    collection := &ConcreteCollection{
        items: []interface{}{"Golang", "Python", "Java"},
    }

    iterator := collection.CreateIterator()
    for iterator.HasNext() {
        item := iterator.Next()
        fmt.Println(item)
    }
}

위의 코드를 실행하면 다음 출력이 생성됩니다:

Golang
Python
Java

위 코드에서는 ConcreteCollection 클래스를 정의하여 Collection 인터페이스를 구현하였으며, CreateIterator() 메서드를 통해 반복자 객체를 반환합니다. 이를 main() 함수에서 사용하여 순회합니다.

4.4 구현 단계 확장: 생성기 함수를 사용하여 반복자 구현 단순화

Golang에서는 생성기 함수(yield)를 사용하여 반복자의 구현을 단순화할 수 있습니다. 다음은 생성기 함수를 사용한 예시입니다:

func GenerateItems() <-chan interface{} {
    items := []interface{}{"Golang", "Python", "Java"}

    out := make(chan interface{})
    go func() {
        defer close(out)
        for _, item := range items {
            out <- item
        }
    }()
    return out
}

func main() {
    for item := range GenerateItems() {
        fmt.Println(item)
    }
}

위 코드에서 우리는 GenerateItems() 함수를 정의하여 읽기 전용 채널(<-chan)을 리턴하고, 이 함수 내부에서 yield를 사용하여 순차적으로 요소를 채널에 보냅니다. main() 함수에서는 이 읽기 전용 채널을 순회하기 위해 range를 사용하고 요소 값을 출력합니다.

이렇게 함으로써 생성기 함수를 사용하여 반복자의 구현을 단순화했습니다.