JavaのIteratorパターンをswiftで頑張って実装した

結城先生の[Java言語で学ぶデザインパターン入門](https://www.amazon.co.jp/増補改訂版Java言語で学ぶデザインパターン入門-結城-浩/dp/4797327030)を読んでいます。
最初の章でIteratorパターンが出てきます。「あ！これswiftではprotocolでうまく表現すればいいやつだ！」と意気揚々と始めます。そして30秒ぐらいで気づきます。

**関連型を持つIteratorProtocolはプロパティとして持てない。**

つまりこういうのがswiftの言語仕様では出来ないです。

```swift:dekinai.swift
protocol Aggregate {
    var iterator: IteratorProtocol { get }
}
```

どう実装しようかな...。と悩んだのですが、RxSwift等で使われている**「抽象クラスと総称型を組み合わせて規定し、実装は全部fatalError()にする。」**というパターンを最初に試してみました。

出来上がったのは以下です。

# 教本通り
associatedtypeを持つprotocolをプロパティで持てないので、`class Iterator<T>: IteratorProtocol ` のように一旦クラスに適合させます。

ただ、この時点で`Element`の具体型を決定するのは遅延したいため総称型を利用します。Aggregate側でも同じように総称型<T>を取り、Iterator側に渡します。

```swift:iteratorPattern.swift
import Foundation

class Aggregate<T> {
    
    var iterater: Iterator<T> {
        fatalError()
    }
    
}

class Iterator<T>: IteratorProtocol {
    
    typealias Element = T
    
    func next() -> T? {
        fatalError()
    }
    
    var hasNext: Bool {
        fatalError()
    }

}

struct Book {
    let name: String
}

final class BookShelfIterator: Iterator<Book> {
    private let bookShelf: BookShelf
    private var index: Int = 0
    
    init(bookShelf: BookShelf) {
        self.bookShelf = bookShelf
    }
    
    override var hasNext: Bool {
        if index < bookShelf.length {
            return true
        } else {
            return false
        }
    }
    
    override func next() -> Book? {
        let book = bookShelf[index]
        index += 1
        return book
    }
    
}

final class BookShelf: Aggregate<Book> {
    private var books: [Book] = []
    
    subscript(index: Int) -> Book {
        return books[index]
    }
    
    func append(_ newElement: Book) {
        books.append(newElement)
    }
    
    var length: Int {
        return books.count
    }
    
    override var iterater: Iterator<Book> {
        return BookShelfIterator(bookShelf: self)
    }
    
}

func main() {
    let bookShelf = BookShelf()
    bookShelf.append(Book(name: "ハリーポッターと賢者の石"))
    bookShelf.append(Book(name: "ハリーポッターと秘密の部屋"))
    bookShelf.append(Book(name: "ハリーポッターとアズカバンの囚人"))
    bookShelf.append(Book(name: "ハリーポッターと炎の御ブレッド"))
    
    let iterator = bookShelf.iterater
    while iterator.hasNext {
        let book = iterator.next()
        print(book?.name)
    }
    
}

main()

// Optional("ハリーポッターと賢者の石")
// Optional("ハリーポッターと秘密の部屋")
// Optional("ハリーポッターとアズカバンの囚人")
// Optional("ハリーポッターと炎の御ブレッド")

```

# ちょっとカスタマイズ
`while` をあまり使いたくないので、`Sequence` プロトコルにも適合させて `for item in items` で表現できるようにします。

```swift:updated.swift
...)

class Iterator<T>: IteratorProtocol, Sequence {
    
    typealias Element = T
    
    func next() -> T? {
        fatalError()
    }
    
    var hasNext: Bool {
        fatalError()
    }

}

...)

final class BookShelfIterator: Iterator<Book> {
    private let bookShelf: BookShelf
    private var index: Int = 0
    
    init(bookShelf: BookShelf) {
        self.bookShelf = bookShelf
    }
    
    override var hasNext: Bool {
        if index < bookShelf.length {
            return true
        } else {
            return false
        }
    }
    
    override func next() -> Book? {
        guard hasNext else {
            return nil
        }
        let book = bookShelf[index]
        index += 1
        return book
    }
    
}

...)

func main() {
    let bookShelf = BookShelf()
    bookShelf.append(Book(name: "ハリーポッターと賢者の石"))
    bookShelf.append(Book(name: "ハリーポッターと秘密の部屋"))
    bookShelf.append(Book(name: "ハリーポッターとアズカバンの囚人"))
    bookShelf.append(Book(name: "ハリーポッターと炎の御ブレッド"))
    
    let iterator = bookShelf.iterater
    for book in iterator {
        print(book.name)
    }
    
}
```

書いてみたのはいいですが、**「冗長すぎひん？」**と思ったのでswiftっぽく書き直してみました。

# swiftっぽく書いてみた
これでええんちゃう？

`Sequence` プロトコルにも、`makeIterator()` という関数が規定されているため同じように扱えます。 `Aggregate(集約)` と `Sequence(連続)` ではやってることは同じですが意味が異なるので、ちょっと意味的には不安な実装ではありますが...。


```swift:swiftIterator.swift
struct Book {
    let name: String
}

struct BookShelfIterator: IteratorProtocol {
    typealias Element = Book
    private let bookShelf: BookShelf
    private var index: Int = 0
    
    init(bookShelf: BookShelf) {
        self.bookShelf = bookShelf
    }
    
    var hasNext: Bool {
        if index < bookShelf.length {
            return true
        } else {
            return false
        }
    }
    
    mutating func next() -> Book? {
        guard hasNext else {
            return nil
        }
        let book = bookShelf[index]
        index += 1
        return book
    }
    
}

struct BookShelf: Sequence {
    typealias Iterator = BookShelfIterator
    
    private var books: [Book] = []
    
    subscript(index: Int) -> Book {
        return books[index]
    }
    
    mutating func append(_ newElement: Book) {
        books.append(newElement)
    }
    
    var length: Int {
        return books.count
    }
    
    func makeIterator() -> BookShelfIterator {
        return BookShelfIterator(bookShelf: self)
    }
    
}

func main() {
    var bookShelf = BookShelf()
    bookShelf.append(Book(name: "ハリーポッターと賢者の石"))
    bookShelf.append(Book(name: "ハリーポッターと秘密の部屋"))
    bookShelf.append(Book(name: "ハリーポッターとアズカバンの囚人"))
    bookShelf.append(Book(name: "ハリーポッターと炎の御ブレッド"))
    
    // 本棚から本を取り出すという自然な表現になっていると思う
    for book in bookShelf {
        print(book.name)
    }
    
}
```

# 実装してみて
RxSwiftではなんだかよく分からない総称型の使い方をしていて「なんだかよく分からないなぁ」と常々思っていたのですが、デザパタを表現しようと思った時にswiftの言語仕様では不都合が出るので、それを回避しつつ表現するための工夫だったのかな？という気づきがありました。

抽象クラスと総称型をうまく使えば、言語仕様の差分を吸収してパターンの表現をしていけそうな事がわかって勉強になりました。でも、できる限りprotocol orientedで表現したいですね。

コンパイラや[存在型](https://qiita.com/ukitaka/items/a993b5d7ed5ae84b1b52)などに詳しくなりたいなぁという感想です。

# 2019/07/06追記
記述可能でした :bow: 

```swift:IteratorPattern.swift
protocol Aggregate {
    associatedtype Iterator: IteratorProtocol
    var iterator: Iterator { get }
}

struct Book {
    let name: String
}

struct BookShelfIterator: IteratorProtocol {
    private let bookShelf: BookShelf
    private var index: Int = 0
    
    init(bookShelf: BookShelf) {
        self.bookShelf = bookShelf
    }
    
    var hasNext: Bool {
        if index < bookShelf.length {
            return true
        } else {
            return false
        }
    }
    
    mutating func next() -> Book? {
        let book = bookShelf[index]
        index += 1
        return book
    }
    
}

struct BookShelf: Aggregate {
    typealias Iterator = BookShelfIterator
    private var books: [Book] = []
    
    subscript(index: Int) -> Book {
        return books[index]
    }
    
    mutating func append(_ newElement: Book) {
        books.append(newElement)
    }
    
    var length: Int {
        return books.count
    }
    
    var iterator: BookShelfIterator {
        return BookShelfIterator(bookShelf: self)
    }
        
}

func main() {
    var bookShelf = BookShelf()
    bookShelf.append(Book(name: "ハリーポッターと賢者の石"))
    bookShelf.append(Book(name: "ハリーポッターと秘密の部屋"))
    bookShelf.append(Book(name: "ハリーポッターとアズカバンの囚人"))
    bookShelf.append(Book(name: "ハリーポッターと炎の御ブレッド"))
    
    var iterator = bookShelf.iterator
    while iterator.hasNext {
        let book = iterator.next()
        print(book?.name)
    }
    
}

main()

```