前言
📣 📣 📣 📢📢📢
☀️☀️点开就是缘分认识一下,我是小冷。是一个兴趣驱动自学练习两年半的的Java工程师。
📒 一位十分喜欢将知识分享出来的Java博主⭐️⭐️⭐️,擅长使用Java技术开发web项目和工具
📒 文章内容丰富:覆盖大部分java必学技术栈,前端,计算机基础,容器等方面的文章
📒 如果你也对Java感兴趣,关注小冷吧,一起探索Java技术的生态与进步,一起讨论Java技术的使用与学习
✏️高质量技术专栏专栏链接: 微服务,数据结构,netty,单点登录,SSM ,SpringCloudAlibaba等
😝公众号😝 : 想全栈的小冷,分享一些技术上的文章,以及解决问题的经验
⏩当前专栏:设计模式系列
⏩专栏代码地址: 代码地址
动动手玩转迭代器模式(iterator)
在Java语言中当我们需要查看数组的时候,我们最常见的方法就是使用循环预语句来遍历数组。
以for循环举例子
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
在for中 i++ 代表每次循环让 i 增加 来做到数组可以从前到后的遍历元素
将 i 抽象出来 形成通用化的模式 就是设计中的 迭代器模式
ps: 迭代器模式常用于 数组和集合遍历中
示例理解
我们用下图的书架来实现一个迭代器模式的示例 :
示例程序的功能内容很简单就是我们将书架中书本的内容按照放入到顺序显示出来
类与接口
接口
迭代器接口 , 想要遍历某一个类这个类值具有两个条件
- 实现了Aggregate接口 表示这个类可以被迭代器遍历
- 有实现了Iterator 接口的适合本类型的迭代器器
public interface Iterator {
public abstract boolean hasNext();
public abstract Object next();
}
public interface Aggregate {
public abstract Iterator iterator();
}
类
Book
放 在书架上的书本类型
public class Book {
private String Name;
public Book(String name) {
this.Name = name;
}
public String getName() {
return Name;
}
}
书架
- 放入书本
- 查看书本(根据书本的
index
来查找) - 获得书本数量
public class BookShelf implements Aggregate {
private Book[] books;
private int last = 0;
public BookShelf(int maxsize) {
this.books = new Book[maxsize];
}
public void appendBook(Book book) {
this.books[last] = book;
last++;
}
public int getLength() {
return last;
}
public Iterator iterator(){
return new BookShelfIterator(this);
}
public Book getBookAt(int index) {
return books[index];
}
用于查找书本的迭代器
- 实现迭代器接口
- 实现对书架的遍历
- 实现拿出功能
public class BookShelfIterator implements Iterator {
private BookShelf bookShelf;
private int index;
public BookShelfIterator(BookShelf bookShelf) {
this.bookShelf = bookShelf;
}
@Override
public boolean hasNext() {
if(index<bookShelf.getLength()){
return true;
}else {
return false;
}
}
@Override
public Object next() {
Book bookAt = bookShelf.getBookAt(index);
index++;
return bookAt;
}
}
示例测试
测试示例,简易的实现了对抽象循环i 来完成迭代书架展示书本内容
public class Test {
public static void main(String[] args) {
BookShelf bookShelf = new BookShelf(4);
bookShelf.appendBook(new Book("A"));
bookShelf.appendBook(new Book("B"));
bookShelf.appendBook(new Book("C"));
bookShelf.appendBook(new Book("D"));
Iterator iterator = bookShelf.iterator();
while (iterator.hasNext()){
Book next = (Book) iterator.next();
System.out.println(next.getName());
}
}
}
迭代器中的角色
在实现了简单的示例程序中 我们来回看一下迭代器中出现了哪几个角色
- 迭代器 iterator 由它来定义一个迭代器规范
- 具体的迭代器 Concretelterator :bookshlefiterator 基于迭代器规范实现了对书架的遍历
- 集合 Aggrrgate 由它来定义一个创建迭代器的规范
- 具体的集合 ConcreteAggregate :bookshelf基于Aggrrgate 规范实现了让这个类可以创建自己的迭代器
迭代器模式的类图
拓展思路
为什么要用
Q : 为什么一定要考虑引入迭代器这样相对麻烦的设计模式呢?
Q : 如果只是数组 直接用循环来迭代不就可以吗 为什么要在集合之外引入迭代器这个角色呢?
A : 一个重要的理由 进入了迭代器之后 可以将遍历与实现分离开
代码片段
while (iterator.hasNext()){
Book next = (Book) iterator.next();
System.out.println(next.getName());
}
这里知识使用率迭代器的 hasnext 和 next 方法,并没有调用 booskshelf 的方法 也就是说这里循环并不依赖 booskshelf 。
那么如果假设 现在开发 booskshelf 的人员决定放弃数组来管理书本 而是选择用Java中的其他容器比如list vector取而代之呢,会如何? 不管 booskshelf 如何变化 只要 booskshelf 方法的 iterator 能正确的返回 iterator示例 即使不对上面的循环代码做任何的改动,代码也可以正常工作
在没有迭代器模式的时候 人们总是用着实现好的类来直接操作 而不是定义一些抽象的规则 这也导致了代码复用性差,他们总是想用具体的类来解决所有的问题
Aggregate 与 iterator 对应
我们在示例中 把booskshelfiterator定义为booskshelf 这个类的迭代器实现,也就是说 booskshelfiterator知道booskshelf 是如何实现的,也正是因为这个实现,我们可以获取下一本书的getBookAt方法。
也就是说如果 booskshelf 发生改变 ,getBookAt这个方法也需要改变,改变的同时,我们也需要去修改
booskshelfiterator,正如Aggregate和iterator对应一样,实现的集合和迭代器也需要是对应的
拓展示例(改为arraylist来存放数据)
只需要将书架类的数据操作方式稍作修改就可以实现替换存储结构,不需要去修改其他代码,操作代码的方式就变化了
public class BookShelf implements Aggregate {
private ArrayList<Book> books;
public BookShelf() {
this.books = new ArrayList<>();
}
public void appendBook(Book book) {
this.books.add(book);
}
public int getLength() {
return books.size();
}
public Iterator iterator(){
return new BookShelfIterator(this);
}
public Book getBookAt(int index) {
return books.get(index);
}
}
测试代码
public static void main(String[] args) {
BookShelf bookShelf = new BookShelf();
bookShelf.appendBook(new Book("A"));
bookShelf.appendBook(new Book("B"));
bookShelf.appendBook(new Book("C"));
bookShelf.appendBook(new Book("D"));
Iterator iterator = bookShelf.iterator();
while (iterator.hasNext()){
Book next = (Book) iterator.next();
System.out.println(next.getName());
}
}
如果还想再通用一些可以使用泛型来将数据类型也变为可以传入的,过于简单所以提供一下思路即可