定义(是什么)
Iterator设计模式是GOF提出的23种设计模式之一,也被叫做迭代模式。
作用是:将容器中所包含的内部对象按照集合的顺序委托给外部类进行访问,是行为模式之一
两个步骤:
- 将需要遍历的集合委托出去
- 一个一个按顺序进行遍历
为什么要使用Iterator设计模式
使用设计模式主要是为了遵循程序开发的6大原则,增强代码的可维护性、可扩展性、可复用性和灵活性。所以可以假想一下,我们如果不是用Iterator迭代设计模式时会怎么做?
有两种可能:
1、在需要便利的类中进行遍历。来看这个例子
public class Book{
......
}
public class BookList{
private List<Book> bookList = new ArrayList<Book>();
public void addBook(Book book){
......
}
public void removeBook(Book book){
......
}
public boolean hasNext(){
......
}
public boolean next(){
......
}
//在类中减需要遍历的一个一个取出
public Book forEachBookListToOne(){
//实现遍历操作的代码
......
}
}
缺点:违反了程序设计的单一原则,既承担了对集合的增删的操作,又需要对集合进行遍历输出,耦合度太高。
2、将集合的数据细节暴露出去,给外部类进行遍历访问操作。
List<Book> list = new BookList().getBookList();
for(Book book : list){
......
}
WARN:总结不使用Iterator模式的缺点
1. 容器类本身承担了太多的功能,既要添加删除、又要提供遍历访问
2. 容器类在遍历访问时往往需要保存遍历的状态,这样在删除或添加时,容器引起混乱和冲突
使用迭代器模式
以上是Java中的Iterator模式的类图,
--------List接口(角色:Aggregate)---------
public interface List<E> {
......
Iterator<E> iterator();
......
}
此处只显示iterator迭代模式相关的代码,其余的接用省略符号替代
List接口中有一个iterator()方法持有一个Iterator迭代器的实例,想要遍历该元素的集合,可以调用该方法去得到这个迭代器。
--------ArrayList接口(角色:ConcreteAggregate)---------
public class ArrayList<E> {
......
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
......
}
}
ArrayList实现了List接口的iterator方法,返回一个内部类的实例,这个实例包含了对集合中元素的迭代等操作
--------Iterator接口(角色:Iterator)---------
public interface Iterator<E> {
.......
boolean hasNext();
E next();
.......
}
Iterator接口负责提供对集合进行遍历,hasNext方法判断集合是否可以调用next方法,next()方法则是取得当前下标的元素并将下标只想下一个元素。
即:next()方法由两个操作。取出当前元素、将下标状态指向下一个迭代的元素
--------------Itr类(角色:ConcreteIterator)------------,继承了Iterator接口,并在java中是ArrayList的内部类。包含了对list集合中的元素的迭代操作。
private class Itr implements Iterator<E> {
int cursor; // 迭代器游标,默认值0
int lastRet = -1; // 默认值-1标识没有找到改下表元素
int expectedModCount = modCount;
Itr() {}
//判断迭代器中的下标是否等于集合的元素个数
public boolean hasNext() {
return cursor != size;
}
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
//将集合中的数组委托给迭代器类
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
......
}
public void forEachRemaining(Consumer<? super E> consumer) {
......
}
//判断迭代时集合是否被修改,假如被修改(增删改操作),则抛出异常
final void checkForComodification() {
//modCount 是集合修改时自动+1
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
Itr时Iterator的实现类,hasNext方法判断下标是否与ArrayList类中的元素长度一致,不一致则返回true,可调用next方法;一致则返回false,已迭代最后一个元素。
next方法中,将ArrayList类中的成员变量elementData数组委托给迭代器,返回当前只想的数组的元素,并将下标指向下一个迭代元素。
简述Iterator中登场的角色:
- Iterator(迭代器):该角色负责定义按顺序逐个遍历元素的接口(API)。在以上程序中,由Iterator扮演这个角色,它定义了两个方法。其中,hasNext 方法用于判断是否存在下一个元素,next 方法用于获取该元素
- ConcreteIterator(具体的迭代器):该角色负责实现Iterator角色所定义的接口(API)。以上程序中,由 Itr 类扮演这个角色。该角色半酣了遍历集合所需要的信息,用于持有元素实例的信息保存在elementData 中,指向下一个元素的下标保存在cursor中。
- Aggregate(集合):该角色定义创建Iterator角色的接口(API),这个接口是一个方法,会创建出“会按顺序访问我内部元素的迭代器”。以上程序中由List接口扮演这个角色
- ConcreteAggregate(具体的集合):该角色负责实现Aggregate角色所定义的接口(API)。会创建出具体的Iterator角色,即ConcreteIterator角色。以上程序中由ArrayList扮演这个角色。
WARN:
其中,Aggregate和Iterator对应,当Aggregate角色的具体实现的API发生了改变,则Iterator的具体实现也需要相应的改变。因为Iterator需要知道Aggregate中是怎么实现的,才能对这个集合做出遍历等操作。
优点:
1、简化的遍历的结构,提供了统一的接口,隐藏了集合的数据细节,可以直接对集合进行遍历
2、实现了功能分离,将集合委托给外部类访问,符合类的设计原则
3、提供了多种方式访问集合(升序、倒叙、跳跃式等等)
引用的文章 https://blog.csdn.net/elise_zhou/article/details/45689161