所谓迭代器,它的核心作用就是将遍历和实现分离开来,在遍历的同时不需要暴露对象的内部表示。
迭代器(iterator)是Java中我们非常熟悉的东西了,数据结构如List和Set都内置了迭代器,我们可以用它提供的方法来顺序地访问一个聚合对象中每个元素。
有时候,我们会定义某些容器类,这些类中包含了大量相同类型的对象。如果你想给这个容器类的对象直接提供迭代的方法,如hasNext,next,first等,那么就可以自定义一个迭代器。然而通常情况下,我们不需要自己再实现一个迭代器,因为Java标准库提供了java.util.Iterator接口,你可以用容器类实现该接口,然后再实现需要的迭代器方法。
这种设计模式就是迭代器模式 ,它的核心作用就是将遍历和实现分离开来,在遍历的同时不需要暴露对象的内部表示。迭代器模式非常容易理解,你可能已经非常熟悉。但我们还是举个具体的例子来介绍下这种模式,接着引出Kotlin中相关的语法特性,继而进行改良。
方案1:实现Iterator接口 data class Book (val name: String)class Bookcase (val books: list<Book>): Iterator<Book> { private val iterator: Iterator<Book> init { this .iterator = books.iterator() } override fun hasNext () = this .iterator.hasNext() override fun next () = this .iterator.next() }val bookcase = Bookcase(listOf(Book("Dive into Kotlin" ),Book("Thinking in Java" )))while (bookcase.hasNext()) { println("The book is ${bookcase.next().name} " ) } The book name is Dive into Kotlin The book name is Thinking in Java
由于Bookcase对象拥有与List实例相同的迭代器,我们就可以直接调用后者迭代器所有的方法。一种更简洁的遍历打印方式如下:
for(book in bookcase) { println("The book name is ${book.name}") }
方案2:重载iterator方法 Kotlin却有更好的解决方案。Kotlin有一个非常强大的语言特性,那就是利用operator关键字内置了很多运算符重载功能。我们就可以通过重载Bookcase类的iterator方法,实现一种语法上更加精简的版本:
data class Book (val name: String)class Bookcase (val books:List<Book>) { operator fun iterator () : Iterator<Book> = this .books.iterator() }
这样我们用一行代码就实现了以上所有效果。由于Kotlin支持扩展函数,这意味着我们可以给所有的对象都内置一个迭代器。
方案3:通过扩展函数 假设现在的Book是引入的一个类,你并不能修改它的源码,那么如何用扩展的语法来给Bookcase类对象增加迭代的功能:
data class Book (val name: String) {}class Bookcase (val Books: list<Book>) {}operator fun Bookcase.iterator () : Iterator<Book> = books.iterator()
代码依旧非常简洁,假如想对迭代器的逻辑有更多的控制权,那么也可以通过object表达式来实现:
operator fun Bookcase.iterator () :Iterator<Book> = object : Iterator<Book> { val iterator = books.iterator() override fun hasNext () = iterator.hasNext() override fun next () = iterator.next() }
总的来说,迭代器模式并不是一种很常用的设计模式,但通过它我们可以进一步了解Kotlin中的扩展函数的应用,以及运算符重载功能的强大之处。