本文参考学习了《图解设计模式》中的代码实现和原理解释
迭代器模式
简介
Iterator 模式用于在数据集合中按照顺序遍历集合。就类似于我们的循环,一个个去遍历一个集合中的所有元素。
示例代码
首先我们思考一个书本和书架的关系,显然,书架可以存储多本书,而且一本书的不同副本都可以存储在书架上。那么我们未来需要将书上的各个信息都获取到,我们可以设置一个迭代器,去一个个遍历书架上的书籍信息。
- 代码实现
- Book 类
/**
* Book实体类
*/
public class Book {
private String name;
public Book(String name) {
this.name = name;
}
public String getName(){
return this.name;
}
}
-
Aggregate 接口
-
定义了一个迭代器方法,子类去做对应的实现
-
用于未来需要拓展实现时,可以复用的接口,未来拓展新的类,比如需要知道大型停车场中所有的车辆信息,那么也只需要实现一个停车场去实现这个接口即可。
-
/**
* Aggregate本身是一个存储多个元素的集合
* 其定义了迭代器的接口
* 它需要利用这个迭代器去遍历自己存储的元素
*/
public interface Aggregate {
Iterator iterator();
}
-
BookShelf 类
-
表示书架:
-
定义了书架该有的功能,比如获取书籍,添加书籍
-
创建迭代器,遍历获取书籍信息
-
-
/**
* 书架,存放着很多书
* 它的主要功能是获取书
* 添加书籍
*/
public class BookShelf implements Aggregate{
private Book[] bookShelf;
private int lastIndex = 0;
public BookShelf(int maxSize) {
this.bookShelf = new Book[maxSize];
}
public boolean appendBook(Book book){
if(book==null){
return false;
}
bookShelf[lastIndex++] = book;
return true;
}
public int getBookCount(){
return lastIndex;
}
public Book getBook(int index){
if(index >= 0 && index < bookShelf.length){
return bookShelf[index];
}
return null;
}
@Override
public Iterator iterator() {
return new BookShelfInterator(this);
}
}
- BookShelfInterator 类
- 表示书架的迭代器
- 实现了interator 接口,需要实现其 hasNext() 和 next() 方法实现遍历
- 表示书架的迭代器
public class BookShelfInterator implements Iterator {
private BookShelf bookShelf;
private int bookIndex = 0;
private int bookCount;
public BookShelfInterator(BookShelf bookShelf) {
this.bookShelf = bookShelf;
bookCount = bookShelf.getBookCount();
}
@Override
public boolean hasNext() {
return this.bookIndex < this.bookCount;
}
@Override
public Book next() {
return this.bookShelf.getBook(this.bookIndex++);
}
}
- 测试类
public class TestInterator {
public static void main(String[] args) {
BookShelf bookShelf = new BookShelf(10);
bookShelf.appendBook(new Book("Java教程"));
bookShelf.appendBook(new Book("C++教程"));
bookShelf.appendBook(new Book("python入门"));
Iterator bookShelfIterator = bookShelf.iterator();
while(bookShelfIterator.hasNext()){
Book book = (Book) bookShelfIterator.next();
System.out.println(book.getName());
}
}
}
运行结果:
迭代器模式中出现的角色
-
迭代器 interator,即 iterator 接口。其声明了 hasNext() 和 next() 方法
-
真正的迭代器 ,BookShelfInterator 类,其实现了具体的迭代方法
-
Aggregate 集合,负责定义创建迭代器角色的接口,这个接口是一个方法,会根据实际的需要创建出一个适合自己类型的迭代器去遍历自己保存的元素。
-
具体的 Aggregate ,由 BookShelf 承担,其存储着许多 Book 元素。其通过实现 iterator 方法创建适合自己类型的迭代器,也就是上面的真正的迭代器。
迭代器模式的特点
- 不管实现如何变化,都可以使用迭代器
让我们思考一下,如果我们没有定义迭代器,我们会如何实现遍历 Aggregate 里的元素呢?
是不是通过一个循环,然后判断一下当前遍历的长度是否超出了 Aggregate 里的元素的长度,如果没有,就获取 Book,如果超出了就结束循环。
这种方式有什么问题呢?
采取这种遍历的方式,会将遍历的行为完全交给 Aggregate 去执行了。当未来我们需要修改一下 Aggregate 的存储类型时,比如从数组改成List。如果我们在程序中调用了很多次循环遍历操作,那么我们就需要逐一去修改原来的循环,而使用迭代器,这些循环操作统一都变为了如下的代码结构:
while(bookShelfIterator.hasNext()){
Book book = (Book) bookShelfIterator.next();
System.out.println(book.getName());
}
那么未来当我们把数组结构改成 List 时,我们只需要去修改对应实体类的方法及其迭代器的实现即可,不需要一个个去修改各个位置上的循环。
例如,我把书籍的数组存储改为 list,我只需要修改下述书架的部分逻辑即可:
/**
* 书架,存放着很多书
* 它的主要功能是获取书
* 添加书籍
*/
public class BookShelf implements Aggregate{
private List<Book> bookShelf;
private int lastIndex = 0;
public BookShelf(int maxSize) {
this.bookShelf = new ArrayList<>(maxSize);
}
public boolean appendBook(Book book){
if(book==null){
return false;
}
return bookShelf.add(book);
}
public int getBookCount(){
return bookShelf.size();
}
public Book getBook(int index){
if(index >= 0 && index < bookShelf.size()){
return bookShelf.get(index);
}
return null;
}
@Override
public Iterator iterator() {
return new BookShelfInterator(this);
}
}
这里都不用改迭代器的逻辑,就可以正常执行了。
并且不论未来我们定义了什么其他的实体类,无论是车辆还是书籍,要实现对应集合对象中元素的遍历操作,都可以使用 iterator 。我们要做的只是实现 Aggregate 接口,然后定义我们自己的方法就好。
即实现了遍历和实现分开。
未来的拓展
迭代器远不止顺序遍历,可以根据需要设计逆向迭代,甚至是跳跃式迭代。或者又能向前又能向后迭代的迭代器。