一、引入
当我们使用循环遍历数组中的数据时,通常会使用如下代码:
for(int i = 0; i< arr.length; i++){
System.out.println(arr[i]);
}
此时我们可以将这个自增变量i
进行抽象化,通用化,并达到遍历效果,从而形成了一个新的设计模式,叫做迭代器模式。
二、示例程序
此处我们使用一段将书放到书架上,并把名字显示出来的代码,使用iterator
模式进行演示
-
Aggregate
接口 是所要遍历的集合的借口,实现了该接口的类将成为一个可以保存多个元素的集合,就像数组一样。public interface Aggregate{ // 用于生成一个用于遍历集合的迭代器 Iterator iterator(); }
-
接下来我们创建
Iterator
接口,用于遍历集合中的元素,其作用是相当于循环语句中的循环变量,此处我们只编写最简单的Iterator
接口。public interface Iterator{ // 判断是否存在下一个元素 boolean hasNext(); // 读取下一个元素 Object next(); }
-
创建书籍的数据传输对象
Book
/**. * 创建书籍的数据传输对象 * @param name 书籍的名称 */ public record Book(String name) {}
-
创建
BookShelf
类,该类作为集合处理,实现Aggregate
接口,用于存储书籍/**. * 实现存储书籍的效果 */ public class BookShelf implements Aggregate{ private Book [] books; private int last = 0; public BookShelf(int maxSize){ this.books = new Book[maxSize]; } /**. * 通过索引获取书本 * @param index 索引位置 * @return 对象的书籍 */ public Book getBookAt(int index){ return books[index]; } /**. * 添加书籍到书架中 * @param book 需要添加的书籍 */ public void appendBook(Book book){ this.books[last] = book; last++; } /**. * 获取当前书架的容量 * @return 数组当前的容量大小 */ public int getLength(){ return last; } @Override public Iterator iterator() { return new BookShelIterator(this); } }
-
创建书架迭代类
BookShelfIterator
,实现迭代器方法。/**. * 用于书架中书籍的迭代 */ public class BookShelIterator implements Iterator { /**. * 书架对象 */ private BookShelf bookShelf; /**. * 当前索引,指向书籍的下标 */ private int index; /**. * 初始化书架,以及初始索引 * @param bookShelf */ public BookShelIterator(BookShelf bookShelf) { this.bookShelf = bookShelf; this.index = 0; } /**. * 判断是否还存在下一个元素 * @return */ @Override public boolean hasNext() { return index < bookShelf.getLength(); } /**. * 返回对应元素 * @return 返回对应的元素对象 */ @Override public Object next() { // 创建通过索引获取的对象 Book bookAt = bookShelf.getBookAt(index); // 增加索引获取下一位 index++; // 返回当前获取到的数据 return bookAt; } }
-
此时我们的准备工作已经完成可以进行测试
public static void main(String[] args) { BookShelf bookShelf = new BookShelf(3); bookShelf.appendBook(new Book("张三")); bookShelf.appendBook(new Book("李四")); bookShelf.appendBook(new Book("王五")); Iterator iterator = bookShelf.iterator(); while (iterator.hasNext()) { Book next = (Book)iterator.next(); System.out.println("next.name() = " + next.name()); } }
此时控制台便会输出
next.name() = 张三 next.name() = 李四 next.name() = 王五
-
此时我们的测试示例使用迭代器来遍历书架中的书籍,便成功实现,通过
书架迭代器
获取迭代器的实例对象,只要while
条件中的hasNext()
方法为true
,我们便可以通过next()
方法获取到书籍对象,一本本遍历出来了。
三、如何实现迭代器模式
- 必须包含的四个组成部分
Iterator
也就是迭代器
用于定义按顺序诸葛遍历元素的接口,在示例程序中我们使用的Iterator
就是这个,它定义了两个方法,即hasNext()
和next()
,分别用于判断是否存在下一个元素和获取该元素。ConcreteIterator
也就是具体的迭代器
用于实现迭代器中所定义的方法,就像咱们示例程序中的BookShelfIterator
,其中包含了遍历集合所需要的信息,Aggregate
(集合)
也就是我们创建迭代器所定义的接口,会创建出按照顺序访问保存在内部的元素。ConcreteAggregate
(具体的集合)
用于实现集合的接口,创建具体的迭代器ConcreteIterator
,在示例程序中为BookShelf
类,它实现了iterator
这个方法。
Iterator
模式的类图
四、为什么要引入Iterator
设计模式
引入Iterator
模式后,可以将遍历与实现分离开来,当我们进行迭代遍历的时候,只是使用了Iterator
的 hasNext()
和next()
方法,并没有使用 BookShelf
的方法,也就是说我们的while
循环并不依赖于BookShelf
的实现。
五、思考
如果书的数量超过了最初指定的容量大小,就无法继续向书架中添加书籍,请大家使用java.util.ArrayList
修改程序,确保当书的容量超过最初指定的书架容量也能继续向书架中添加书本