zoukankan      html  css  js  c++  java
  • 迭代器模式-统一集合的遍历方式

    公号:码农充电站pro
    主页:https://codeshellme.github.io

    今天来介绍迭代器模式Iterator Design Pattern),它还有另一个名字,叫作游标模式Cursor Design Pattern)。

    1,遍历集合元素

    现在的高级语言(比如 C++JavaPython 等)都支持很多种集合(比如 ListMapSet 等),用于存储对象。

    同时这些高级语言也都原生支持了迭代器,这使得遍历集合变得非常简单。

    下面我们来看下,如果不使用迭代器,如何遍历集合。

    Java ArrayList 为例,创建 list,并加入 5 个元素:

    ArrayList<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);
    list.add(4);
    list.add(5);
    

    用 for 循环遍历 list

    for (int i = 0; i < list.size(); i++) {
        System.out.println(list.get(i));
    }
    

    如果不用迭代器,只能使用 get 方法,将集合中的元素一个个取出。

    如果使用迭代器遍历元素,就可以像下面这样:

    Iterator<Integer> i = list.iterator();
    while (i.hasNext()) {
        System.out.println(i.next());
    }
    

    先用 iterator 方法返回迭代器,再用 hasNext 方法查看迭代器中是否还有元素,如果有元素则用 next 方法取出元素。

    更简单的方式是使用 forEeah 循环:

    for (Object i: list) {
        System.out.println(i);
    }
    

    forEach 循环(对迭代器的一种包装)是 Java 5 中引入的遍历集合的方式,这种方式不再需要获取迭代器,甚至不需要知道所遍历的是哪种数据结构,也不需知道其中存储的是什么类型的数据。

    Java 集合框架与迭代器

    Java 中的 SetListQueue 都实现了 Collection 接口,该接口中的 iterator 方法返回一个迭代器,用于遍历集合中的元素。

    这使得所有的 Collection 对象的遍历都变得非常简单,使用 forEach 循环即可:

    for (Object o: collection) {
        // 遍历元素
    }
    

    2,迭代器模式

    迭代器模式提供了一种方法,用于遍历集合对象中的元素,而又不暴露其内部的细节

    一般的迭代器都要实现一个迭代器接口,该接口至少包含两个方法,即 hasNextnext

    public interface Iterator {
        boolean hasNext();
        Object next();
    }
    

    hasNext 方法用于查看集合中是否还有下一个元素;next 方法用于返回集合中的下一个元素,并移动指向元素的游标。

    Java 中的 Iterator 接口中还有一个 remove 方法,其实这个方法的必要性并不大,所以它的默认实现是抛出 UnsupportedOperationException 异常。因此,对于 remove 方法,不需要给予太多的关注。

    这使得每个集合中的元素的访问方式都是统一的。

    一个完整的迭代器模式一般会包含集合迭代器两部分,为了达到基于接口而非实现编程的原则,还抽象出了两个接口,其类图如下:

    在这里插入图片描述

    Collection 中的 iterator 方法用于返回当前对象的迭代器,从而遍历集合中的元素。

    迭代器模式将集合对象的遍历操作从集合类中拆分出来,放到迭代器类中,使得两者的职责更加单一。

    这其实用到了单一职责原则:一个类应该只有一个引起变化的原因。

    3,迭代器不支持增删

    迭代器的目的是为了方便元素的遍历,而如果在遍历的过程中增删元素,则会导致元素重复遍历或者遍历不到

    下面来看下这种错误是如何产生的。

    假设一个列表中有 abcd 四个元素,我们从前往后遍历。刚开始时,游标 cursor 指向 a

    在这里插入图片描述

    当遍历到 b 时,cursor 指向 b

    在这里插入图片描述

    遍历时删除元素

    如果此时将 a 元素删除,那么所有其它元素都会前移一个位置:

    在这里插入图片描述

    从而,这时的游标就会指向 c,这就会导致 b 没有被遍历到。

    遍历时增加元素

    如果在遍历到 b 的时候,在表头增加一个元素 x,那么所有的元素都会后移一个位置:

    在这里插入图片描述

    从而,这时的游标依然是指向 a,这就会导致 a 被重复遍历了。

    因此,在使用迭代器遍历元素的时候都会禁止增删元素。

    Java 如何禁止增删元素

    为了禁止在遍历时增删元素,Java 的做法是,在遍历元素时会进行 checkForXXX 操作,目的是检查是否有元素增删,如果有增删的情况,则抛出异常。

    4,总结

    迭代器模式是为了方便元素的遍历,它统一了集合的遍历方式。它将元素的遍历操作从集合中拆分出来,从而使得两者得以解耦。

    大部分高级语言都原生支持迭代器,这使得开发人员可以专注于业务实现,而不用过多的关心底层实现。

    如果在迭代器的遍历过程中增删元素,则会导致元素的遍历发生错误,因此迭代器中一般不支持增删元素。

    (本节完。)


    推荐阅读:

    装饰者模式-动态的包装原有对象的行为

    命令模式-将请求封装成对象

    适配器模式-让不兼容的接口得以适配

    外观模式-简化子系统的复杂性

    模板方法模式-封装一套算法流程


    欢迎关注作者公众号,获取更多技术干货。

    码农充电站pro

  • 相关阅读:
    HDU1879 kruscal 继续畅通工程
    poj1094 拓扑 Sorting It All Out
    (转)搞ACM的你伤不起
    (转)女生应该找一个玩ACM的男生
    poj3259 bellman——ford Wormholes解绝负权问题
    poj2253 最短路 floyd Frogger
    Leetcode 42. Trapping Rain Water
    Leetcode 41. First Missing Positive
    Leetcode 4. Median of Two Sorted Arrays(二分)
    Codeforces:Good Bye 2018(题解)
  • 原文地址:https://www.cnblogs.com/codeshell/p/14244944.html
Copyright © 2011-2022 走看看