はじめに
本記事はJava言語で学ぶデザインパターン入門を見ながら
JavaではなくKotlinで実装してみようというものです。
調べてみる
まずはIteratorとは何かというところから調べましょう。
WikipediaではIteratorについて次のように解説されています。
プログラミング言語において配列やそれに類似する集合的データ構造の
各要素に対する繰り返し処理の抽象化である。
配列や類似する集合的データ構造の各要素に対する繰り返し処理の抽象化です。
つまりは配列・リスト・独自データ構造などのデータの集まりでも
同じインタフェースで繰り返し処理ができるようにすることがIteratorの役目ということですね。
実装してみる
Iterator
ある集合体クラスを繰り返すためのインタフェースを定義します。
interface Iterator {
fun hasNext() : Boolean
fun next() : Object
}
Aggregate
集合体クラスを表すインタフェースを定義します。
interface Aggregate {
fun iterator() : Iterator
}
Book
集合体クラスの各項目をBookクラスとして定義します。
data class Book(val name : String)
BookShelf
集合体クラスとしてBookShelfを定義
BookShelfは集合体クラスとしたいのでAggregateを実装します。
Aggregateを実装するとIteratorを取得できるようになりますので、
BookShelfの各要素に対して繰り返し処理を行うことができるようになります。
class BookShelf(maxsize : Int) : Aggregate {
private val books : Array<Book?> = arrayOfNulls(maxsize)
private var last : Int = 0
val length : Int get() = last
fun getBookAt(index : Int) : Book? {
return books[index]
}
fun appendBook(book : Book) {
this.books[last] = book
last++
}
override fun iterator(): Iterator {
return BookShelfIterator(this)
}
}
BookShelfIterator
BookShelfのためのIteratorをBookShelfIteratorとして定義
集合体クラスによって配列の要素を取得・追加するメソッドは異なります。
次のように集合体クラスごとにIteratorを実装したクラスを作成しインタフェースを揃えてやります。
class BookShelfIterator(bookShelf : BookShelf) : Iterator{
private val bookShelf : BookShelf = bookShelf
private var index : Int = 0
override fun hasNext(): Boolean = (index < bookShelf.length)
override fun next(): Object {
val book = bookShelf.getBookAt(index)
index++
return book as Object
}
}
Main
上記で定義したクラスとインタフェースを使って、
集合体の各項目に対して繰り返し処理を実行します。
fun main(args : Array<String>) {
val bookShelf : BookShelf = BookShelf(4)
bookShelf.appendBook(Book("Around the World in 80 Days"))
bookShelf.appendBook(Book("Bible"))
bookShelf.appendBook(Book("Cinderella"))
bookShelf.appendBook(Book("Daddy-Long-Legs"))
val iterator : Iterator = bookShelf.iterator()
while (iterator.hasNext()) {
val book : Book = iterator.next() as Book
println(book.name)
}
}
次のようにFor文でぐるぐるまわすパターンだと、
配列やリストなど集合体を表すパターンごとに繰り返し処理を変えなければなりません。
これをなくすためのデザインパターンがIteratorなんですね。
val array : Array<Book?> = arrayOfNulls(4)
array[0] = Book("Around the World in 80 Days")
array[1] = Book("Bible")
array[2] = Book("Cinderalla")
array[3] = Book("Daddy-Long-Legs")
for(i in 0..3){
// Indexでアクセスしたり、またはクラス固有のメソッドを呼び出したり
println(array[i]?.name)
}
Iteratorは自然に触れているデザインパターンですよね、
ForEachとか処理できるのもIteratorを実装しているからなわけですしね。