十四、迭代器模式—— 一个一个的遍历 #和设计模式一起旅行#

套路要深…

故事背景

今天要介绍一下迭代器,首先简单说明一下,什么是迭代器,为什么要使用迭代器。
迭代器(Iterate) 的意思就是反复做某件事情。

那为什么要反复做某件事情呢,比如我们有个容器里面装了很好东西(这些东西都是同一类型的),要从容器中取每一个东西出来,就要反复去做一个取出的事情。

故事主角

迭代器模式 : 提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。

迭代器模式类图

在迭代器模式结构中包含聚合迭代器两个层次结构,并在迭代器中使用到了工厂方法模式。

在迭代器结构图中有如下几个角色:

  • Iterator (抽象迭代器): 定义了访问和遍历元素的接口。
  • ConcreteIterator(具体的迭代器):实现了抽象迭代器接口,完成对聚合对象的遍历操作。
  • Aggregate(抽象的聚合类):存储和管理元素对象,声明一个创建迭代器的方法。充当抽象迭代器工厂的角色。
  • ConcreteAggregate(具体的聚合类):实现了抽象聚会类申明的创建迭代器方法。

武功修练

通过上面对迭代器的了解和认识我们看一下Java集合框架中迭代器的使用。主要看一下ArrayList、LinkedList、HashSet。这三个是集合中的三个常用类,但是它们的实现机制是不一样的。这里对实现机制就不进行讲解,不懂的朋友可以自行查找资料。

首先看一下这三个类的结构图:

三个类图

其中都是实现了 Iterable接口。下面我们再看一下这个Iterable接口

// 这个就是Aggregate(抽象的聚合类)
public interface Iterable<T> {
    // 申明 创建迭代器的方法
    Iterator<T> iterator();

    // 其他默认实现
    default void forEach(Consumer<? super T> var1) {
        Objects.requireNonNull(var1);
        Iterator var2 = this.iterator();

        while(var2.hasNext()) {
            Object var3 = var2.next();
            var1.accept(var3);
        }

    }

    default Spliterator<T> spliterator() {
        return Spliterators.spliteratorUnknownSize(this.iterator(), 0);
    }
}

在来看一下Iterator 接口

// Iterator (抽象迭代器)
public interface Iterator<E> {
    boolean hasNext(); // 是否有下一个元素

    E next();//下一个元素

    // 其他默认实现
    default void remove() {
        throw new UnsupportedOperationException("remove");
    }

    default void forEachRemaining(Consumer<? super E> var1) {
        Objects.requireNonNull(var1);

        while(this.hasNext()) {
            var1.accept(this.next());
        }

    }
}

从上面的;类图和源码中,可以看到ArrayList、LinkedList、HashSet,是ConcreteAggregate(具体的聚合类),具体的聚合类中实现创建迭代器以及实现具体的迭代器!

如下是ArrayList源码:

// 在ArrayList创建了一个迭代器
public Iterator<E> iterator() {
        return new Itr();
    }

    /**
     * An optimized version of AbstractList.Itr
     * jdk1.8版本
     */
    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];
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

    // 其他方法
    }

如下是LinkedList 实现迭代器的部分代码:

public Iterator<E> descendingIterator() {
        return new LinkedList.DescendingIterator();
    }

private class DescendingIterator implements Iterator<E> {
        private final LinkedList<E>.ListItr itr;

        private DescendingIterator() {
            this.itr = LinkedList.this.new ListItr(LinkedList.this.size());
        }

        public boolean hasNext() {
            return this.itr.hasPrevious();
        }

        public E next() {
            return this.itr.previous();
        }

        public void remove() {
            this.itr.remove();
        }
    }

hashSet的源码实现就不进行说明了,感兴趣的朋友可以自行查看。

通过上面简单的类图和源码分析,发现了这几个类使用了迭代器模式。

举个简单的小例子说明一下迭代器的好处:

class IteratorDemo {
   public static void process(Collection c) {
        Iterator i = c.iterator(); //创建迭代器对象

        //通过迭代器遍历聚合对象
        while(i.hasNext()) {
            System.out.println(i.next().toString());
        }
   }

    public static void main(String args[]) {
        Collection persons;
persons = new ArrayList(); //创建一个ArrayList类型的聚合对象
        persons.add("2");
        persons.add("5");
        persons.add("3");
        persons.add("7");
        persons.add("0");
        persons.add("4");

        process(persons);
    }
}

如果需要更换聚合类型,如将List改成Set即可,迭代遍历的代码无需进行修改。

总结

迭代器模式简化了聚合类对象的元素的遍历,封装了聚合类具体的遍历实现细节,能够实现聚合对象的内部数据和存储分离,使得聚合类的职责更加专一,同时提供统一的接口,方便客户端操作。

Next 期待下一篇吧!下一篇讲讲组合模式!

参考


如果您觉得这篇博文对你有帮助,请点赞或者喜欢,让更多的人看到,谢谢!

如果帅气(美丽)、睿智(聪颖),和我一样简单善良的你看到本篇博文中存在问题,请指出,我虚心接受你让我成长的批评,谢谢阅读!
祝你今天开心愉快!


欢迎访问我的csdn博客,我们一同成长!

不管做什么,只要坚持下去就会看到不一样!在路上,不卑不亢!

博客首页 : http://blog.csdn.net/u010648555

猜你喜欢

转载自blog.csdn.net/u010648555/article/details/80962716
今日推荐