本文实例代码:https://github.com/JamesZBL/java_design_patterns
迭代器(Iterator)模式又称游标模式,是集合类型对外提供统一的顺序访问元素而隐藏内部的实现细节的一种方式,是一种行为模式。
迭代器在 Java 的集合类中非常常见,我们使用迭代器来遍历集合中的每一个元素。迭代器在 ArrayList 的使用通常是这样的:
1 | String[] array = new String[]{"百度", "阿里", "腾讯"}; |
输出:1
2
3百度
阿里
腾讯
我们使用 Iterator 接口的一个实例来访问这个 List 实例,Iterator 接口非常小巧,定义了两个方法:
1 | public interface Iterator<E> { |
Java 中的“容器”类的之间的关系:
Collection 接口继承自 Iterable:
1 | public interface Iterable<T> { |
所以可以理解为所有的集合都是可遍历的,因为集合就是一系列元素的“容器”。而 Collection 接口中的 iterator() 方法返回一个 Iterator 接口的引用,所以可以对所有的 Collection 的子类调用 iterator() 方法来获取这个容器实例的迭代器。对于不同的容器的实现,其内部数据结构是不同的,所以具体的迭代方式自然也不尽相同,但是它们都通过这个统一的接口方法来获取迭代器,迭代的实现被巧妙的隐藏了。
实例
现实生活中有一个常用的场景和迭代器的工作方式非常相似,那就是在图书馆中寻找自己想要的一本书,我们通常的做法是找到这个类目的书架,然后按一定的顺序一本一本的找,这个过程可以大致视为迭代器遍历书架这个容器。
我们把这个书架上的书分为三个大类:IT、小说和卡通,用一个枚举类来表示:
ItemType.java1
2
3public enum ItemType {
IT, FICTION, CARTOON
}
和 JDK 中提供给我们的 Iterator 接口类似,我们也定义一个 Iterator 接口:
ItemIterator.java
1 | public interface ItemIterator { |
定义一个书架类 BookShelf,它持有一个 List
BookShelf.java
1 | public class BookShelf { |
现在来定义专门为 BookShelf 服务的迭代器,它实现 ItemIterator 接口:
BookShelfIterator.java
1 | public class BookShelfIterator implements ItemIterator { |
这里我们间接的使用了 List 接口提供的方法 get() 来获取第 n 个元素,其内部实现同样被隐藏了,这里只是演示遍历的过程,因此不必考虑 List 的内部数据结构。
显然,这和 Collection 中的结构是不同的,BookShelfIterator 持有 BookShelf 的引用,而不是由 BookShelf 来生成适用于它自身的迭代器,虽然看起来比较别扭,不过还是符合实际情况的,迭代器要拿到书架这个对象才能遍历它。如果大范围的使用,还是应当仿照 Collection 中的设计思路,避免出现过多的类,给系统的复杂度造成负担。
现在拿一个装满书的书架来试一下这个迭代器的效果:
App.java
1 | public class Application { |
总结
迭代器模式提供一种方法顺序访问一个聚合对象中各个元素, 而又无须暴露该对象的内部表示。迭代器模式关乎遍历集合的解决思路是把游标在元素之间移动的职责转交给迭代器,而不是集合对象自己。
迭代器模式的优点有:
1、它支持以不同的方式遍历一个集合合对象
2、迭代器模式简化了集合类
3、在同一个聚合上可以有多个遍历
4、使用迭代器模式,新建聚合类和迭代器,无须修改原有代码