Iterator

デザインパターンとは

デザインパターンとはオブジェクト思考開発における先人たちが作り上げてきた便利な設計図です。

Gang of Four通称Gofが1994年に出版した『オブジェクト指向における再利用のためのデザインパターン』の中で23個の設計図が紹介されています。

Note

デザインパターンのサンプルコードはSwift4でまとめます。

イテレータパターンとは?

Itaratorパターンは要素の集まりを持つオブジェクトに対して順番にアクセスを提供するためのパターンです。

下記のようなコードではiがIteratorの役割を持っています。

for i in 0...10{}

iの動きは0から10まで最初から順番にスキャンをしています。ここで使われているiの動きを抽象化したものがIteratorパターンです。

サンプルコード

サンプルコードでは、本棚にある本に順番にアクセスして名前を取得するプログラムを作成しました。

Protocol

プロトコルは2つあります。この2つの基本概念は今回のサンプル以外でもそのまま使うことができます。

Aggregate

要素の塊を保有する対象のクラスに準拠させることで、要素を順番に取得できるようにします。・

protocol Aggregate {
    func iterator() -> Iterator
}

Iterator

戻り値から予測できるかと思いますが、次のオブジェクトがあるかをhasNextで判定し、存在すればnextメソッドを使って取得します。

protocol Iterator {
    func hasNext() -> Bool
    mutating func next() -> Any
}

Bookクラス(取り出す実体)

class Book {
    let name: String
    init(name: String) {
        self.name = name
    }
}

本棚クラス

このクラスで注目すべきはiterateメソッドです。自分を別のクラス渡しています。

本棚クラスの中で処理をするのではなく、別のクラスで行うことでクラス間の結合を弱めクラスを1つの部品として再利用しやすくしています。

class BookShelf: Aggregate {
    var books:[Book] = []
    
    func appendBook(book: Book){
        books.append(book)
    }
    func getBook(index: Int) -> Book {
        return books[index]
    }
    func iterator() -> Iterator {
        return BookShelfIterator(bookShelf: self)
    }
}

本棚イテレータ

class BookShelfIterator: Iterator {
    private let bookShelf: BookShelf
    private var index = 0
    init(bookShelf: BookShelf) {
        self.bookShelf = bookShelf
    }
    func hasNext() -> Bool {
        if bookShelf.books.count > index {
            
            return true
        }
        return false
    }
    
    func next() -> Any {
        let book = bookShelf.getBook(index: index)
        index += 1
        return book
        
    }
}

呼び出し元

let bookShelf = BookShelf()
//本棚に本を追加
bookShelf.appendBook(book: Book(name: "マンガ"))
bookShelf.appendBook(book: Book(name: "小説"))
bookShelf.appendBook(book: Book(name: "技術書"))

//作った本棚でイテレータを作成
let iterator = BookShelfIterator(bookShelf: bookShelf)
while(iterator.hasNext()){
    let book = iterator.next()
    if let book = book as? Book{
        print(book.name)
    }
}

コンソール

マンガ
小説
技術書

コード一覧

import UIKit

protocol Aggregate {
    func iterator() -> Iterator
}
protocol Iterator {
    func hasNext() -> Bool
    func next() -> Any
}

class Book {
    let name: String
    init(name: String) {
        self.name = name
    }
}

class BookShelf: Aggregate {
    var books:[Book] = []
    
    func appendBook(book: Book){
        books.append(book)
    }
    func getBook(index: Int) -> Book {
        return books[index]
    }
    func iterator() -> Iterator {
        return BookShelfIterator(bookShelf: self)
    }
}

class BookShelfIterator: Iterator {
    private let bookShelf: BookShelf
    private var index = 0
    init(bookShelf: BookShelf) {
        self.bookShelf = bookShelf
    }
    func hasNext() -> Bool {
        if bookShelf.books.count > index {
            
            return true
        }
        return false
    }
    
    func next() -> Any {
        let book = bookShelf.getBook(index: index)
        index += 1
        return book
        
    }
}

let bookShelf = BookShelf()
//本棚に本を追加
bookShelf.appendBook(book: Book(name: "マンガ"))
bookShelf.appendBook(book: Book(name: "小説"))
bookShelf.appendBook(book: Book(name: "技術書"))

//作った本棚でイテレータを作成
let iterator = BookShelfIterator(bookShelf: bookShelf)
while(iterator.hasNext()){
    let book = iterator.next()
    if let book = book as? Book{
        print(book.name)
    }
}

参考文献

増補改訂版Java言語で学ぶデザインパターン入門

[iOS 8] Swiftでデザインパターン No.2 Iterator

Iterator design pattern in Swift

Swiftで学ぶデザインパターン6 (Iterator パターン)

デザインパターン「Iterator」