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

套路要深…

故事背景

今天要介绍一下迭代器,首先简单说明一下,什么是迭代器,为什么要使用迭代器。
迭代器(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

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 成长之路 设计师:Amelia_0503 返回首页