设计模式学习笔记(12)迭代器

本文实例代码:https://github.com/JamesZBL/java_design_patterns

迭代器(Iterator)模式又称游标模式,是集合类型对外提供统一的顺序访问元素而隐藏内部的实现细节的一种方式,是一种行为模式。

迭代器在 Java 的集合类中非常常见,我们使用迭代器来遍历集合中的每一个元素。迭代器在 ArrayList 的使用通常是这样的:


String[] array = new String[]{"百度", "阿里", "腾讯"};

List<String> list = Arrays.asList(array);

Iterator<String> iterator = list.iterator();

while (iterator.hasNext()) {

    System.out.println(iterator.next());

}

输出:


百度

阿里

腾讯

我们使用 Iterator 接口的一个实例来访问这个 List 实例,Iterator 接口非常小巧,定义了两个方法:


public interface Iterator<E> {

    // 判断是否有后继元素

    boolean hasNext();

    // 获取下一个元素的引用,执行此方法后,“游标”自动向后移动

    E next();

}

Java 中的“容器”类的之间的关系:

Collection 接口继承自 Iterable:


public interface Iterable<T> {

    Iterator<T> iterator();

}

所以可以理解为所有的集合都是可遍历的,因为集合就是一系列元素的“容器”。而 Collection 接口中的 iterator() 方法返回一个 Iterator 接口的引用,所以可以对所有的 Collection 的子类调用 iterator() 方法来获取这个容器实例的迭代器。对于不同的容器的实现,其内部数据结构是不同的,所以具体的迭代方式自然也不尽相同,但是它们都通过这个统一的接口方法来获取迭代器,迭代的实现被巧妙的隐藏了。

实例

现实生活中有一个常用的场景和迭代器的工作方式非常相似,那就是在图书馆中寻找自己想要的一本书,我们通常的做法是找到这个类目的书架,然后按一定的顺序一本一本的找,这个过程可以大致视为迭代器遍历书架这个容器。

我们把这个书架上的书分为三个大类:IT、小说和卡通,用一个枚举类来表示:

ItemType.java


public enum ItemType {

  IT, FICTION, CARTOON

}

和 JDK 中提供给我们的 Iterator 接口类似,我们也定义一个 Iterator 接口:

ItemIterator.java


public interface ItemIterator {

  boolean hasNext();

  Item next();

}

定义一个书架类 BookShelf,它持有一个 List<ItemType> 类型的引用,表示书架上所有图书的集合:

BookShelf.java


public class BookShelf {

  private List<Item> items;

  public BookShelf() {

    items = new ArrayList<>();

    items.add(new Item(ItemType.FICTION, "西游记"));

    items.add(new Item(ItemType.FICTION, "水浒传"));

    items.add(new Item(ItemType.FICTION, "三国演义"));

    items.add(new Item(ItemType.FICTION, "红楼梦"));

    items.add(new Item(ItemType.CARTOON, "阿衰"));

    items.add(new Item(ItemType.CARTOON, "七龙珠"));

    items.add(new Item(ItemType.CARTOON, "火影忍者"));

    items.add(new Item(ItemType.IT, "设计模式-可复用面向对象软件的基础"));

    items.add(new Item(ItemType.IT, "重构-改善既有代码的设计"));

    items.add(new Item(ItemType.IT, "Effective Java"));

    items.add(new Item(ItemType.IT, "Java编程思想"));

  }

  public List<Item> getItemList() {

    List<Item> list = new ArrayList<>();

    list.addAll(items);

    return list;

  }

}

现在来定义专门为 BookShelf 服务的迭代器,它实现 ItemIterator 接口:

BookShelfIterator.java


public class BookShelfIterator implements ItemIterator {

  private ItemType type;

  private BookShelf shelf;

  private int idx;

  public BookShelfIterator(ItemType type, BookShelf shelf) {

    this.type = type;

    this.shelf = shelf;

    this.idx = -1;

  }

  @Override

  public boolean hasNext() {

    return -1 != getNexIdx();

  }

  @Override

  public Item next() {

    idx = getNexIdx();

    if (-1 != idx) {

      return shelf.getItemList().get(idx);

    }

    return null;

  }

  private int getNexIdx() {

    List<Item> list = shelf.getItemList();

    int tempIdx = idx;

    boolean found = false;

    while (!found) {

      tempIdx++;

      if (tempIdx >= list.size()) {

        tempIdx = -1;

        break;

      }

      if (list.get(tempIdx).getType().equals(type)) {

        break;

      }

    }

    return tempIdx;

  }

}

这里我们间接的使用了 List 接口提供的方法 get() 来获取第 n 个元素,其内部实现同样被隐藏了,这里只是演示遍历的过程,因此不必考虑 List 的内部数据结构。

显然,这和 Collection 中的结构是不同的,BookShelfIterator 持有 BookShelf 的引用,而不是由 BookShelf 来生成适用于它自身的迭代器,虽然看起来比较别扭,不过还是符合实际情况的,迭代器要拿到书架这个对象才能遍历它。如果大范围的使用,还是应当仿照 Collection 中的设计思路,避免出现过多的类,给系统的复杂度造成负担。

现在拿一个装满书的书架来试一下这个迭代器的效果:

App.java


public class Application {

  private static final Logger LOGGER = LoggerFactory.getLogger(Application.class);

  public static void main(String[] args) {

    // 查找小说

    ItemIterator iterator = new BookShelfIterator(ItemType.FICTION, new BookShelf());

    LOGGER.info("正在查找小说类图书");

    while (iterator.hasNext()) {

      Item nextItem = iterator.next();

      LOGGER.info("找到了符合条件的图书,书名为:{}", nextItem.toString());

    }

    // 查找IT

    ItemIterator iterator2 = new BookShelfIterator(ItemType.IT, new BookShelf());

    LOGGER.info("正在查找IT类图书");

    while (iterator2.hasNext()) {

      Item nextItem = iterator2.next();

      LOGGER.info("找到了符合条件的图书,书名为:{}", nextItem.toString());

    }

    // 查找漫画

    ItemIterator iterator3 = new BookShelfIterator(ItemType.CARTOON, new BookShelf());

    LOGGER.info("正在查找漫画类图书");

    while (iterator3.hasNext()) {

      Item nextItem = iterator3.next();

      LOGGER.info("找到了符合条件的图书,书名为:{}", nextItem.toString());

    }

  }

}

总结

迭代器模式提供一种方法顺序访问一个聚合对象中各个元素, 而又无须暴露该对象的内部表示。迭代器模式关乎遍历集合的解决思路是把游标在元素之间移动的职责转交给迭代器,而不是集合对象自己。

迭代器模式的优点有:

1、它支持以不同的方式遍历一个集合合对象

2、迭代器模式简化了集合类

3、在同一个聚合上可以有多个遍历

4、使用迭代器模式,新建聚合类和迭代器,无须修改原有代码

个人博客同步更新,获取更多技术分享请关注:郑保乐的博客

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,636评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,890评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,680评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,766评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,665评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,045评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,515评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,182评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,334评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,274评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,319评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,002评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,599评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,675评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,917评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,309评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,885评论 2 341

推荐阅读更多精彩内容

  • 1 场景问题# 1.1 工资表数据的整合## 考虑这样一个实际应用:整合工资表数据。 这个项目的背景是这样的,项目...
    七寸知架构阅读 2,501评论 0 53
  • 一、基础知识:1、JVM、JRE和JDK的区别:JVM(Java Virtual Machine):java虚拟机...
    杀小贼阅读 2,360评论 0 4
  • 文/南陌花开 《江山梦之谋妃天下》目录 上一章 江山梦之谋妃天下5 第六章 书房议事 慎德堂,顾相书房。这里不仅是...
    南陌花开阅读 327评论 0 1
  • 突然有种感悟,原来人生中有很多东西并非我们表面看到的那样,其实我们以为的得到,很有可能就是一种把我们迷惑了的失去;...
    雨后的太阳阅读 190评论 0 1
  • 这两回007写作班的作业,我基本是在最后时间交上去的。 分析下原因,主要是这段时间工作任务重,多个条线的项目抢着上...
    Rose海洋阅读 434评论 0 2