๊ธ€ ์ž‘์„ฑ์ž: ๊ฐœ๋ฐœํ•˜๋Š” ํ›ˆ์ด

๋ฐ˜๋ณต์ž ํŒจํ„ด(Iterator Pattern)

๋ฐ˜๋ณต์ž ํŒจํ„ด์€ ์ปฌ๋ ‰์…˜์˜ ๋‚ด๋ถ€ ๊ตฌํ˜„์„ ๋…ธ์ถœํ•˜์ง€ ์•Š์œผ๋ฉด์„œ ์ปฌ๋ ‰์…˜์˜ ๋ชจ๋“  ์š”์†Œ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

๋ฐ˜๋ณต์ž ํŒจํ„ด์€ ์ปฌ๋ ‰์…˜ ๊ฐ์ฒด๋กœ๋ถ€ํ„ฐ ๋ฐ˜๋ณต์ ์œผ๋กœ ์ปฌ๋ ‰์…˜ ์š”์†Œ์— ์ ‘๊ทผํ•˜๋Š” ์—ญํ• ์„ ๋ถ„๋ฆฌํ•ด๋‚ด๋Š” ํŒจํ„ด์ž…๋‹ˆ๋‹ค. ๋ฐ˜๋ณต์ž ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋ฉด ์ปฌ๋ ‰์…˜์€ ์ž์‹ ์˜ ์š”์†Œ๋“ค์„ ๊ด€๋ฆฌํ•˜๋Š” ์—ญํ• ์—๋งŒ ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ๊ณ , ์–ด๋–ค ์š”์ฒญ์— ์˜ํ•ด ํŠน์ •ํ•œ ์š”์†Œ๋ฅผ ์™ธ๋ถ€๋กœ ์•Œ๋ ค์ฃผ๋Š” ์ฑ…์ž„์€ Iterator์—๊ฒŒ ๋ชจ๋‘ ๋งก๊ธธ ์ˆ˜ ์žˆ๊ฒŒ ๋˜์ฃ .

์ •์˜์—์„œ๋Š” ์ปฌ๋ ‰์…˜์˜ ๋‚ด๋ถ€ ๊ตฌํ˜„์„ ์™ธ๋ถ€๋กœ ๋…ธ์ถœํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ํ•˜๋Š”๋ฐ์š”, ์ด ์˜๋ฏธ๋Š” ์‹ค์ œ๋กœ ์‚ฌ์šฉ๋˜๋Š” ์ปฌ๋ ‰์…˜์ด ๋ฐฐ์—ด์ธ์ง€, ๋ฆฌ์ŠคํŠธ์ธ์ง€์™€ ๊ฐ™์€ ์‹ค์ œ ๊ตฌ์กฐ์™€๋Š” ์ „ํ˜€ ์ƒ๊ด€์—†์ด ๊ฐ ์›์†Œ๋“ค์— ์ ‘๊ทผ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ƒฅ Iterator๋ฅผ ๋ฐ›์•„์„œ ๋์— ๋„๋‹ฌํ•  ๋•Œ๊นŒ์ง€ ๋‹ค์Œ ์›์†Œ๋ฅผ Iterator์—๊ฒŒ ๋‹ค์Œ ์›์†Œ๋ฅผ ์š”์ฒญํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋˜๋‹ˆ๊นŒ์š”.

๊ทธ๋Ÿผ ๋ฐ˜๋ณต์ž ํŒจํ„ด์ด ์–ด๋–ป๊ฒŒ ๊ตฌ์„ฑ๋˜๋Š”์ง€ ์•Œ์•„๋ด…์‹œ๋‹ค.

 

๋ฐ˜๋ณต์ž ํŒจํ„ด ์ดํ•ดํ•˜๊ธฐ

์œ„ ๊ทธ๋ฆผ์ฒ˜๋Ÿผ ๋ฐ˜๋ณต์ž ํŒจํ„ด์€ ํฌ๊ฒŒ ์„ธ ๊ฐ€์ง€ ์š”์†Œ๋กœ ๊ตฌ๋ถ„๋ฉ๋‹ˆ๋‹ค.

๋จผ์ € Iterable ํ”„๋กœํ† ์ฝœ๊ณผ ์ด๋ฅผ ์ฑ„ํƒํ•˜๋Š” ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. Iterable์€ ๋ง ๊ทธ๋Œ€๋กœ ์ˆœํšŒ๊ฐ€ ๊ฐ€๋Šฅํ•œ ์š”์†Œ๋“ค์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฐ์ฒด๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์šฐ๋ฆฌ๊ฐ€ ์ปฌ๋ ‰์…˜์ด๋ผ๊ณ  ๋ถ€๋ฅด๋Š”, ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์š”์†Œ๋“ค์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฐ์ฒด๊ฐ€ Iterable์ด ๋˜๊ฒ ์ฃ . Iterable์€ ์ปฌ๋ ‰์…˜์„ ๊ด€๋ฆฌํ•˜๋Š” ์ฑ…์ž„์„ ๊ฐ€์ง€๊ฒŒ ๋˜๋Š”๋ฐ์š”, ๋ฐ˜๋ณต์ž ํŒจํ„ด์„ ์œ„ํ•ด์„œ ์ด ๊ฐ์ฒด๊ฐ€ ํ•˜๋Š” ์ผ์€ ๋‹จ ํ•œ ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ๊ฐ€ Iterable ๊ฐ์ฒด ์•ˆ์— ์žˆ๋Š” ์›์†Œ์— ์ˆœ์ฐจ์ ์œผ๋กœ ์ ‘๊ทผํ•˜๊ณ  ์‹ถ์„ ๋•Œ, ์›์†Œ์— ์ ‘๊ทผํ•˜๋Š” ์ฑ…์ž„์„ ๊ฐ€์ง€๋Š” ๊ฐ์ฒด๋Š” Iterator๋ฅผ ์ƒ์„ฑํ•ด ๋ฐ˜ํ™˜ํ•ด์ฃผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. 

์ด ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ createIterator๊ฐ€ ๋˜๊ฒ ์ฃ . 

์ด์ œ ๋ฐ˜๋ณต์ž ํŒจํ„ด์˜ ํ•ต์‹ฌ์ด ๋˜๋Š” Iterator๋ฅผ ํ™•์ธํ•ด๋ด…์‹œ๋‹ค. Iterator๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋‘ ๊ฐ€์ง€ ๋ฉ”์„œ๋“œ๋ฅผ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์ œ๊ณตํ•ด์š”. ๋ฌผ๋ก  ๊ตฌํ˜„์— ๋”ฐ๋ผ์„œ ๋‹ค๋ฅธ ํŽธ๋ฆฌํ•œ API๋ฅผ ์ œ๊ณตํ•  ์ˆ˜๋„ ์žˆ๊ฒ ์ฃ . hasNext๋Š” ์•„์ง ํƒ์ƒ‰ํ•˜์ง€ ์•Š์€ ์›์†Œ๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๋ฉ”์„œ๋“œ์ด๊ณ , next๋Š” ๋‹ค์Œ ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฉ”์„œ๋“œ์—์š”. ์ด iterator๋Š” ์ปฌ๋ ‰์…˜์—์„œ ๊ฐ๊ฐ ๊ตฌํ˜„ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์™ธ๋ถ€์—์„œ๋Š” ์ปฌ๋ ‰์…˜์˜ ๋‚ด๋ถ€ ๊ตฌํ˜„์„ ์•Œ์ง€ ๋ชปํ•œ ์ฑ„๋กœ hasNext์™€ next ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ†ตํ•ด ์›์†Œ๋“ค์„ ์ฝ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

Iterator Pattern ๋งŒ๋“ค์–ด๋ณด๊ธฐ

protocol Iterable {
    associatedtype Iterator
    func makeIterator() -> Iterator
}

protocol Iterator {
    associatedtype Element
    func hasNext() -> Bool
    func next() -> Element?
}

์ดํ„ฐ๋ ˆ์ดํ„ฐ ํŒจํ„ด์„ ์œ„ํ•ด์„œ ๊ฐ€์žฅ ๋จผ์ € Iterable๊ณผ Iterator ํ”„๋กœํ† ์ฝœ์„ ์ •์˜ํ–ˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ๊ทธ๋ฆผ์—์„œ ๋ดค๋˜ ๊ทธ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ทธ๋Œ€๋กœ ์ œ๊ณตํ•˜๊ณ  ์žˆ์–ด์š”. 

final class defaultIterator<T>: Iterator {
    typealias Element = T
    private var items: [Element] = []
    private var current = 0

    init(items: [Element]) {
        self.items = items
    }

    func next() -> Element? {
        guard hasNext() else { return nil }
        defer { self.current += 1 }

        return items[current]
    }

    func hasNext() -> Bool {
        current < items.count
    }
}

๊ทธ๋ฆฌ๊ณ  Iterator์˜ ๊ตฌ์ฒด ํƒ€์ž…์„ ์ •์˜ํ–ˆ๋Š”๋ฐ์š”, ๋จผ์ € ์ดˆ๊ธฐํ™” ์‹œ์ ์— ์–ด๋–ค ๋ฐฐ์—ด์„ ์ž…๋ ฅ๋ฐ›๊ณ , ํ˜„์žฌ ํƒ์ƒ‰ ์ค‘์ธ ์š”์†Œ๋ฅผ ํ‘œ์‹œํ•˜๋Š” ์ปค์„œ ์—ญํ• ์„ ํ•˜๋Š” ๋ณ€์ˆ˜์ธ current๋ฅผ ์ •์˜ํ–ˆ์Šต๋‹ˆ๋‹ค. hasNext๋Š” ์ด ์ปค์„œ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋‹ค์Œ ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š”์ง€ ํŒ๋‹จํ•˜๊ณ , next์—์„œ๋Š” current๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ๋ฝ‘์•„๋‚ด ๋ฐ˜ํ™˜์„ ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. defer๋ฅผ ์จ๋ณด๊ณ  ์‹ถ์–ด์„œ ํ•œ ๋ฒˆ ์จ๋ดค์–ด์š”ใ…Žใ…Ž

๊ทธ๋Ÿผ ์ด ํŒจํ„ด์„ ์–ด๋–ป๊ฒŒ ์‘์šฉํ•˜๋ฉด ์ข‹์„์ง€ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋ฅผ ๋งŒ๋“ค์–ด๋ณผ๊ฒŒ์š”.

์ดํ„ฐ๋ ˆ์ดํ„ฐ ํŒจํ„ด์˜ ์ •์˜๋‚˜ ์ฑ…์˜ ์˜ˆ์ œ์—์„œ ๊ฐ€์žฅ ์™€๋‹ฟ์•˜๋˜ ์ ์ด ๋‚ด๋ถ€ ๊ตฌํ˜„์„ ์•Œ์ง€ ๋ชปํ•ด๋„ ๋ฐ˜๋ณต์„ ๋Œ๋ฆด ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด์—ˆ๋Š”๋ฐ์š”, ๊ทธ๋ž˜์„œ list์™€ map ๋‘ ์ข…๋ฅ˜์˜ ์ปฌ๋ ‰์…˜์— ๋Œ€ํ•œ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๊ณ  ์ดํ„ฐ๋ ˆ์ดํ„ฐ ํŒจํ„ด์„ ์ ์šฉํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค.

final class MapCollection: Iterable {
    private var map: [String: String] = [:]

    func add(element: String, for key: String) {
        map.updateValue(element, forKey: key)
    }

    func makeIterator() -> defaultIterator<String> {
        return defaultIterator<String>(items: self.map.values.map({ $0 }))
    }
}

final class ListCollection: Iterable {
    private var list: [String] = []

    func add(element: String) {
        list.append(element)
    }

    func makeIterator() -> defaultIterator<String> {
        return defaultIterator<String>(items: self.list)
    }
}

๋‘ ํด๋ž˜์Šค ๋ชจ๋‘ Iterable ํ”„๋กœํ† ์ฝœ์„ ์ •์˜ํ•˜์ง€๋งŒ ๊ฐ™์€ ํƒ€์ž…์˜ Iterator๋ฅผ ์ƒ์„ฑํ•ด์„œ ๋ฐ˜ํ™˜ํ•ด์ฃผ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ์ด ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ์šฉ์ž์˜ ์ž…์žฅ์—์„œ๋Š” ListCollection์ด๋‚˜ MapCollection์ด ์ด๋ฆ„์„ ํ†ตํ•ด ๋‚ด๋ถ€์ ์œผ๋กœ ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„๋˜์—ˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ์„์ง€๋Š” ๋ชฐ๋ผ๋„, ๋ฐ˜๋ณต๋ฌธ์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ๋‚ด๋ถ€ ๊ตฌํ˜„์„ ์•Œ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋ƒฅ makeIterator()๋ฅผ ๋ถˆ๋Ÿฌ์„œ Iterator๋ฅผ ์–ป๊ณ , ์›์†Œ๋ฅผ ํƒ์ƒ‰ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋˜๊ธฐ ๋•Œ๋ฌธ์ด์ฃ .

let map = MapCollection()
let list = ListCollection()

map.add(element: "1", for: "1")
map.add(element: "2", for: "2")
map.add(element: "3", for: "3")

list.add(element: "11")
list.add(element: "22")
list.add(element: "33")

let iterators = [map.makeIterator(), list.makeIterator()]

for iterator in iterators {
    while iterator.hasNext() {
        print(iterator.next() ?? "0")
    }
}

// 3
// 2
// 1
// 11
// 22
// 33

์ด๋ ‡๊ฒŒ ๊ฐ๊ฐ์˜ ํƒ€์ž…์— ๋Œ€ํ•œ ๋ฐ˜๋ณต๋ฌธ์„ ๋งŒ๋“ค์ง€ ์•Š์•„๋„, iterator๋ฅผ ํ†ตํ•ด ๋ชจ๋“  ์š”์†Œ์— ๋Œ€ํ•œ ํƒ์ƒ‰์ด ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ฐ€๋Šฅํ•ด์ง‘๋‹ˆ๋‹ค.

๋งˆ๋ฌด๋ฆฌ

Iterator Pattern์˜ ํ•ต์‹ฌ์€ ๋‚ด๋ถ€ ๊ตฌํ˜„์„ ๊ฐ์ถ”๋ฉด์„œ๋„ ์‚ฌ์šฉ์ž๊ฐ€ ์ปฌ๋ ‰์…˜ ๊ฐ์ฒด๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๋ชจ๋“  ์›์†Œ๋“ค์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋™์‹œ์— ์›์†Œ๋ฅผ ํƒ์ƒ‰ํ•˜๋Š” ์—ญํ• ์„ ์ปฌ๋ ‰์…˜ ๊ฐ์ฒด์—์„œ ๋ถ„๋ฆฌํ•ด๋‚ผ ์ˆ˜ ์žˆ์ฃ . 

์‚ฌ์‹ค ์Šค์œ„ํ”„ํŠธ์—์„œ๋Š” IteratorProtocol ์ด๋ผ๋Š” Foundation ํ”„๋กœํ† ์ฝœ์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

์ด ์˜ˆ์‹œ์ฒ˜๋Ÿผ ์Šค์œ„ํ”„ํŠธ๋Š” Sequence ์— ๋Œ€ํ•ด์„œ Iterator๋ฅผ ์ œ๊ณตํ•˜๋Š”๋ฐ์š”, for animal in animals์™€ ๊ฐ™์€ ๋ฌธ๋ฒ•์ด ๊ฐ€๋Šฅํ•œ ์ด์œ ๋„

๋‚ด๋ถ€์ ์œผ๋กœ๋Š” ์ด๋ ‡๊ฒŒ Iterator ํŒจํ„ด์„ ํ†ตํ•ด ๊ตฌํ˜„์ด ๋˜์–ด์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

Sequence ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜๋ฉด makeIterator ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด iterator๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๊ณ , IteratorProtocol์„ ์ฑ„ํƒํ•ด next() ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด ๋‹ค์Œ ์š”์†Œ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋Š” ๊ตฌํ˜„์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์ฃ . 

 

์ด๋ ‡๊ฒŒ ํ•ด์„œ Iterator ํŒจํ„ด์„ ๊ณต๋ถ€ํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค. Swift์—์„œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ชจ๋“  ์ปฌ๋ ‰์…˜์— Iterator๊ฐ€ ์ œ๊ณต๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ง์ ‘ ๊ตฌํ˜„ํ•  ์ผ์€ ๋งŽ์ง€ ์•Š๊ฒ ์ง€๋งŒ, ์™œ Iterator ํŒจํ„ด์ด ํ•„์š”ํ•œ์ง€, ์–ด๋–ค ์ ์—์„œ ์œ ์šฉํ•œ ์ง€ ์กฐ๊ธˆ์€ ์•Œ๊ฒŒ ๋œ ๊ฒƒ ๊ฐ™์•„์š”. 

 

์˜ค๋Š˜๋„ ์ฝ์–ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!