据说微信搜索《Java鱼仔》会变动强哦!java
本文收录于JavaStarter ,里面有我完整的Java系列文章,学习或面试均可以看看哦git
(一)什么是迭代器模式
迭代器模式应该是23种设计模式中,程序员最容易理解的设计模式了,由于迭代器模式在平常的开发过程当中常用到。以最多见的循环为例:程序员
for(int i=0;i<arr.length;i++){ System.out.print(arr[i]); }
上面的这段代码经过循环逐一将arr的下标加1,从而实现了遍历数组的功能。github
可是经过循环实现遍历的话依赖于集合对象内部,所以就有了一种能顺序访问集合对象中各个元素,又无需依赖对象内部表示的设计模式--迭代器模式。面试
(二)迭代器模式中的角色
迭代器模式中的角色主要有4种:设计模式
一、迭代器接口(Iterator):定义访问和遍历集合元素的接口,通常包含next()和hasNext()方法。数组
二、具体迭代器(ConcreteIterator):该角色用于实现迭代器接口,迭代器的核心遍历逻辑在这里实现。微信
三、集合接口(Aggregate):集合接口定义了建立迭代器的接口方法,内部定义了iterator方法。ide
四、具体集合(ConcreteAggregate):该角色用于实现集合接口,他会建立出具体的Iterator角色。学习
看到这里若是你以为比较疑惑没关系,下面会经过代码的方式来加深理解。
(三)迭代器模式的代码实现
首先说一下这段代码的场景,定义了一个教室的类,又定义了学生的类,实现遍历教室中学生的功能。
代码列表以下:
interface Aggregate:集合接口 interface Iterator:迭代器接口 class Classroom:教室类,实现集合接口,属于具体的集合 class ClassroomIterator:教室迭代器,实现迭代器接口,属于具体的迭代器 class Student:学生类
首先把迭代器模式中的两个接口角色定义出来:
public interface Aggregate { Iterator iterator(); } public interface Iterator { boolean hasNext(); Object next(); }
接着定义学生类:
@Data @AllArgsConstructor public class Student { private String name; }
接着定义教室类,在教室类中咱们定义了Student集合,以及当前的集合长度和最大长度。同时实现Aggregate接口的iterator方法,这个方法将会返回一个迭代器对象。这个迭代器对象由ClassroomIterator提供
public class Classroom implements Aggregate{ private Student[] students; private int length=0; private int maxSize; public Classroom(int maxSize){ this.maxSize=maxSize; students=new Student[maxSize]; } public Student getStudent(int index){ return students[index]; } public boolean addStudent(Student student){ if (length>=maxSize){ return false; } this.students[length]=student; length++; return true; } public int getLength(){ return this.length; } @Override public Iterator iterator() { return new ClassroomIterator(this); } }
最后就是ClassroomIterator对象了,ClassroomIterator属于迭代器的具体实现,这里须要实现hasNext方法和next方法
public class ClassroomIterator implements Iterator{ private Classroom classroom; private int index; public ClassroomIterator(Classroom classroom){ this.classroom=classroom; this.index=0; } @Override public boolean hasNext() { if (this.index<classroom.getLength()){ return true; } return false; } @Override public Object next() { Student student = classroom.getStudent(index); index++; return student; } }
最后就是使用了,经过迭代器对象,咱们能够直接遍历classroom对象:
public static void main(String[] args) { Classroom classroom=new Classroom(3); classroom.addStudent(new Student("张三")); classroom.addStudent(new Student("李四")); classroom.addStudent(new Student("王五")); Iterator iterator = classroom.iterator(); while (iterator.hasNext()){ Student next = (Student) iterator.next(); System.out.println(next.getName()); } }
(四)迭代器模式的做用
看到这里不少人可能会有疑问,写了一堆,用循环不是更方便吗?迭代器模式最大的做用是将遍历和具体的实现分开,以上面的测试方法为例,遍历时咱们始终只用到了iterator对象,而没有用到classroom,这就意味着咱们以后能够彻底复用这段代码实现遍历。
另外一方面,若是咱们发如今classroom里使用数组存储student,后续没法扩容,想改成List集合,这个时候咱们只须要修改ClassroomIterator和Classroom这两个具体实现角色便可。而不用对使用中的代码作任何修改,就好比上面这段测试遍历代码不须要任何变更。若是用的是for循环或者while循环,就意味着全部用到循环的地方都须要修改代码。
(五)迭代器模式在源码中的应用
迭代器模式的应用咱们在敲代码时确定都用过,迭代器模式最佳实践就是JDK中Iterator接口的设计
public interface Iterator<E> { boolean hasNext(); E next(); default void remove() { throw new UnsupportedOperationException("remove"); } default void forEachRemaining(Consumer<? super E> action) { Objects.requireNonNull(action); while (hasNext()) action.accept(next()); } }
具体的迭代器实现最经常使用的就是集合,随便找个ArrayList看一下源码:
总体的实现逻辑和咱们上面实现的基本上十分类似。
(五)总结
在学习设计模式的时候,会慢慢开始理解为何要设计接口,而不是直接写各类类。若是用具体的类去解决一个个需求,就会致使类之间的强依赖,这些类也难以被拆分出来做为组件复用。我是鱼仔,咱们下期再见!