概述

在 面向对象程式设计里,迭代器模式是一种设计模式,是一种最简单也最常见的设计模式。它可以让使用者透过特定的界面巡访容器中的每一个元素而不用了解底层的实作。

个人理解,这种模式解耦了用户和容器结构之间的关系。使得用户不用了解容器内部结构即可遍历容器的所有元素。

比如:如果你想访问数组中的元素,得用下标,访问集合中的元素得用get方法(当然Java中的集合都已经实现该方法,但是如果没有实现呢?)。

而实现了迭代器模式,你只要拿着他的迭代器,依照统一的流程或者方法进行迭代即可。比如 next 方法或者 hasNext方法。

UML图

从图中可以分析:

迭代器模式由以下角色组成:

  • 迭代器角色(Iterator):迭代器角色负责定义访问和遍历元素的接口。
  • 具体迭代器角色(Concrete Iterator):具体迭代器角色要实现迭代器接口,并要记录遍历中的当前位置。
  • 容器角色(Container):容器角色负责提供创建具体迭代器角色的接口。
  • 具体容器角色(Concrete Container):具体容器角色实现创建具体迭代器角色的接口。这个具体迭代器角色与该容器的结构相关。

代码实例

自己模拟了一个容器,然后自己写了一个 Iterator来访问容器中的元素。

package com.ans;

import java.util.ArrayList;
import java.util.List;

interface iterator<T> {
    public boolean hasNext();
    public T next();
}

class ConcretIterator<T> implements iterator<T> {

    private List<T> list = new ArrayList<T>();
    private int cur = 0;
    public ConcretIterator(List<T> list) {
        this.list = list;
    }
    @Override
    public boolean hasNext() {
        if(cur != list.size()) 
            return true;
        return false;
    }

    @Override
    public T next() {
        T t = null;
        if(this.hasNext()) {
            t = this.list.get(cur++);
        }
        return t;
    }

}

interface Container<T> {
    public boolean add(T t);
    public void remove(T t);
    public iterator<T> iterator();
}

class MyContainer<T> implements Container<T> {
    private List<T> list = new ArrayList<T>();


    public boolean add(T t) {
        return list.add(t);
    }

    public void remove(T t) {
        list.remove(t);
    }
    public iterator<T> iterator() {
        return new ConcretIterator<T>(list);
    }
}


public class IteratorPattern {
    public static void main(String[] args) {
        Container<String> container = new MyContainer<String>();
        container.add("nice");
        container.add("Hello");
        container.add("World");
        iterator<String> it = container.iterator();
        while(it.hasNext()) {
            System.out.println(it.next());
        }
    }
}

运行结果:

nice
Hello
World

从主方法中的访问方式就可以看出来,用户如果不看前面的代码实现,完全不知道我的container的内部结构是怎样的,但是依旧可以将其中的元素遍历出来。

作为对比,我们可以看下标准的JDK源码中是怎么写的:

这是 AbstractList 中的一个得到迭代器的方法:

public Iterator<E> iterator() {
return new Itr();
}

private class Itr implements Iterator<E> {
int cursor = 0;

int lastRet = -1;

int expectedModCount = modCount;
public boolean hasNext() {
        return cursor != size();
}

public E next() {
        checkForComodification();
    try {
    E next = get(cursor);
    lastRet = cursor++;
    return next;
    } catch (IndexOutOfBoundsException e) {
    checkForComodification();
    throw new NoSuchElementException();
    }
}

...
}

原理完全一样,只不过增加了一些安全机制而已。

总结

由上面的讲述,我们可以看出迭代器模式给容器的应用带来以下好处:

1) 支持以不同的方式遍历一个容器角色。根据实现方式的不同,效果上会有差别。

2) 简化了容器的接口。但是在java Collection中为了提高可扩展性,容器还是提供了遍历的接口。

3) 对同一个容器对象,可以同时进行多个遍历。因为遍历状态是保存在每一个迭代器对象中的。

由此也能得出迭代器模式的适用范围:

1) 访问一个容器对象的内容而无需暴露它的内部表示。

2) 支持对容器对象的多种遍历。

3) 为遍历不同的容器结构提供一个统一的接口(多态迭代)。