一、摘要
迭代器模式是与集合共生共死的。一般来说,我们只要实现一个容器,就需要同时提供这个容器的迭代器。使用迭代器的好处是:封装容器的内部实现细节,对于不同的集合,可以提供统一的遍历方式,简化客户端的访问和获取容器内数据。在此基础上,我们可以使用 Iterator 完成对集合的遍历,此外,for 循环和foreach 语法也可以用于遍历集合类。ListIterator 是容器 List容器族特有的双向迭代器。本文要点主要包括:迭代器模式
Iterator 迭代器 与 Iterable 接口
循环遍历 : foreach,Iterator,for 的异同
ListIterator 简述(容器 List 详解)
二、迭代器模式
迭代器模式是与集合共生共死的。一般来说,我们只要实现一个容器,就需要同时提供这个容器的迭代器,就像 Java 中的 Collection (List、Set 等) ,这些容器都有自己的迭代器。假如我们要实现一个新的容器,当然也需要引入迭代器模式,给我们的容器实现一个迭代器。使用迭代器的好处是:封装容器的内部实现细节,对于不同的集合,可以提供统一的遍历方式,简化客户端的访问和获取容器内数据。
但是,由于容器与迭代器的关系太密切了,所以大多数语言在实现容器的同时也提供了相应的迭代器,并且在绝大多数情况下,这些语言所提供的容器和迭代器都可以满足我们的需要。所以,现实中需要我们自己去实现迭代器模式的场景还是比较少见的,我们常常只需要使用语言中已有的容器和迭代器就可以了。
1、定义与结构定义
迭代器(Iterator)模式,又叫做游标(Cursor)模式。GOF给出的定义为:提供一种方法访问一个容器(container)对象中的各个元素,而又不需暴露该容器对象的内部细节。
从定义可见,迭代器模式是为容器而生。我们知道,对容器对象的访问必然涉及到遍历算法。你可以一股脑的将遍历方法塞到容器对象中去,或者,根本不去提供什么遍历算法,让使用容器的人自己去实现。这两种情况好像都能够解决问题。然而,对于前一种情况,容器承受了过多的功能,它不仅要负责自己“容器”内的元素维护(增、删、改、查 等),而且还要提供遍历自身的接口;而且最重要的是,由于遍历状态保存的问题,不能对同一个容器对象同时进行多个遍历,并且还需增加 reset 操作。第二种方式倒是省事,却又将容器的内部细节暴露无遗。迭代器模式角色组成
迭代器角色(Iterator): 迭代器角色负责定义访问和遍历元素的接口;
具体迭代器角色(Concrete Iterator): 具体迭代器角色要实现迭代器接口,并要记录遍历中的当前位置;
容器角色(Container): 容器角色负责定义创建具体迭代器角色的接口;
具体容器角色(Concrete Container): 具体容器角色实现创建具体迭代器角色的接口 —— 这个 具体迭代器角色 与该容器的结构相关。结构图
从结构上可以看出,迭代器模式在客户端与容器之间加入了迭代器角色。迭代器角色的加入,就可以很好的避免容器内部细节的暴露,而且也使得设计符合 单一职责原则。
特别需要注意的是,在迭代器模式中,具体迭代器角色和具体容器角色是耦合在一起的 —— 遍历算法是与容器的内部细节紧密相关的。为了使客户程序从与具体迭代器角色耦合的困境中脱离出来,避免具体迭代器角色的更换给客户程序带来的修改,迭代器模式抽象了具体迭代器角色,使得客户程序更具一般性和重用性,这被称为 多态迭代。适用性
1.访问一个容器对象的内容而无需暴露它的内部表示;
2.支持对容器对象的多种遍历;
3.为遍历不同的容器结构提供一个统一的接口 ( 即,支持多态迭代 )。
2、举例
由于迭代器模式本身的规定比较松散,所以具体实现也就五花八门,我们在此仅举一例。在举例前,我们先来列举一下迭代器模式的实现方式。迭代器角色定义了遍历的接口&#