这是我参与更文挑战的第7天,活动详情查看: 更文挑战
迭代器模式,常⻅见的就是我们⽇常使⽤的iterator
遍历。虽然这个设计模式在我们的实际业务开发中的场景并不多,但却⼏乎每天都要使⽤jdk
为我们提供的list
集合遍历。迭代器模式的特点是实现 Iterable
接⼝,通过next
的⽅式获取集合元素,同时具备对元素的删除等操作。
我们先看一段代码:
public static void test(Collection col){
Iterator it = col.iterator();
while(it.hasNext()){
String s = (String)it.next();
System.out.println(s);
}
}
这个方法类似的逻辑我们经常见到,作用是循环打印一个字符串集合,里面就用到了迭代器模式,java语言已经完整地实现了迭代器模式,Iterator就是迭代器的意思。迭代器的作用就是把容器中的对象一个一个地遍历出来。
迭代器模式的角色
- 抽象容器:一般是一个接口,提供一个iterator()方法,例如java中的Collection接口,List接口,Set接口等。
- 具体容器:就是抽象容器的具体实现类,比如List接口的有序列表实现ArrayList,List接口的链表实现LinkList,Set接口的哈希列表的实现HashSet等。
- 抽象迭代器:定义遍历元素所需要的方法,一般来说会有这么三个方法:取得第一个元素的方法first(),取得下一个元素的方法next(),判断是否遍历结束的方法hasNext(),移出当前对象的方法remove(),
- 迭代器实现:实现迭代器接口中定义的方法,完成集合的迭代。
使用场景
- 当你需要访问一个聚合对象,而且不管这些对象是什么都需要遍历的时候,就应该考虑使用迭代器模式。
- 当需要对聚集有多种方式遍历时,可以考虑去使用迭代器模式。
优缺点
- 遍历方式多样化,对有序列表,我们可以根据需要提供正序遍历,倒序遍历,使用者只需要得到我们实现好的迭代器即可。
- 在一定程度上增加了系统的复杂性。
代码示例
- 我们先定一个抽象的迭代器
//抽象迭代器定义
public interface MyIterator<T> {
T next();
boolean hasNext();
}
- 定义个抽象容器
public interface IcollectionCrud<T> {
void add(T obj);
void remove(T obj);
MyIterator<T> iterator();
}
- 具体实现上面定义的2个迭代器和容器
//具体的迭代器
public class ConcreteIterator<T> implements MyIterator<T> {
private List<T> list ;
private int index = 0;
public ConcreteIterator(List list) {
this.list = list;
}
@Override
public T next() {
T obj = null;
if(this.hasNext()){
obj = this.list.get(index++);
}
return obj;
}
@Override
public boolean hasNext() {
if(index==list.size()){
return false;
}
return true;
}
}
//具体集合增删改成实现类
public class ConcreteCollCrud<T> implements IcollectionCrud<T>{
private List list = new ArrayList();
@Override
public void add(T obj) {
list.add(obj);
}
@Override
public void remove(T obj) {
list.remove(obj);
}
@Override
public MyIterator<T> iterator() {
return new ConcreteIterator(list);
}
}
- 我们用客户端进行调用
public class Client {
public static void main(String[] args) {
IcollectionCrud<String> icollectionCrud = new ConcreteCollCrud<>();
icollectionCrud.add("1");
icollectionCrud.add("2");
icollectionCrud.add("3");
icollectionCrud.add("4");
MyIterator<String> iterator = icollectionCrud.iterator();
while (iterator.hasNext()) {
String str = iterator.next();
System.out.println(str);
}
}
}
结果
1 2 3 4
大家可以看到上面写的是不是跟我们平时jdk提供的集合类遍历是一模一样的。接着我们就看一下jdk是咋实现的。
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());
}
}
这个 Iterator
方法就相当于我们定义的 MyIterator
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
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];
}
...
}
}
上面这个是Iterator的实现类,其实在我们常用的ArrayList中有一个内部实现类Itr ,它就实现了Iterator接口 ,其中hasNext方法和next()方法实现也非常简单,我们继续往下看在ArrayList内部还有几个迭代器对Itr进行了进一步扩展,首先看Listltr :
private class ListItr extends Itr implements ListIterator<E> {
ListItr(int index) {
super();
cursor = index;
}
public boolean hasPrevious() {
return cursor != 0;
}
public int nextIndex() {
return cursor;
}
public int previousIndex() {
return cursor - 1;
}
}
同样迭代器模式在MyBatis中也是必不可少的,感兴趣的大家可以自己看看源码。