type
status
date
slug
summary
tags
category
icon
password
 

一、迭代器模式概述

 
迭代器模式主要作用是解耦容器代码和遍历代码,使用设计模式的主要目的是解耦。
迭代器模式(Iterator Design Pattern),也叫作游标模式(Cursor Design Pattern)。
迭代器模式将集合对象的遍历操作从集合类中拆分出来,放到迭代器类中,让两者的职责更加单一。
 
迭代器模式结构:
  • Collection 集合接口
  • ConcreteCollection 具体集合实现类
  • Iterator 迭代器接口
  • ConcreteIterator 具体迭代器实现类
 
迭代器接口定义:
  • 第一种定义:next() 函数用来将游标后移一位元素,currentItem() 函数用来返回当前游标指向的元素
  • 第二种定义:返回当前元素与后移一位这两个操作,放到了同一个函数 next() 中完成(这也是 Jdk 的实现)
 

二、迭代器模式实现

 

简单实现

 
以 ArrayList 的迭代器为例,使用第一种迭代器接口定义实现:
 
 

简单优化:

 
  • 为了封装迭代器的创建细节,可以在容器中定义一个 iterator() 方法,来创建对应的迭代器
  • 为了能实现基于接口而非实现编程,还需要将这个方法定义在 List 接口中
 
 

三、迭代器模式的优势

 
遍历集合数据有三种方法:for 循环、foreach 循环、iterator 迭代器,其中 foreach 遍历底层也是迭代器,因此遍历集合只有两种方法。
 
  • 解耦容器与遍历逻辑,降低容器复杂性。例如树和图的深度和广度遍历,可以实现 DFSIterator、BFSIterator 两个迭代器类。
  • 容器和迭代器都提供了抽象的接口,方便我们在开发的时候,基于接口而非具体的实现编程。例如,要反向遍历链表,只需将 LinkedIterator 切换为 ReversedLinkedIterator 即可。
  • 每个迭代器独享游标信息。多个不同的迭代器,同时对同一个容器进行遍历互不影响。
 

四、迭代遍历时增删元素

 
同样使用 ArrayList 基于数组的 List 的迭代器进行举例。

遍历时新增元素

 
  • 新增的元素位于迭代器游标之前,数组整体后移,发生重复遍历
  • 新增的元素位于迭代器游标之后,数组整体后移,不影响
 

遍历时删除元素

 
  • 删除的元素位于迭代器游标之前,数组整体前移,丢失游标原来指向的元素
  • 删除的元素位于迭代器游标之后,数组整体前移,不影响
 

解决遍历时集合的变化

 
  • 一种是遍历的时候不允许增删元素
    • 需要确定遍历开始和结束的时间点,该段事件内不允许增删
    • 创建迭代器的时间点作为遍历开始的时间点
    • 结束时间不好确定,遍历可能会中途结束 break,可在 Iterator 实现 finishIteration() 方法,遍历退出时由用户手动调用
  • 另一种是增删元素之后让遍历报错(JDK 采用)
    • ArrayList 中定义一个成员变量 modCount,记录集合被修改的次数,集合每调用一次增加或删除元素的函数,就会给 modCount 加 1。
    • 迭代器中定义一个成员变量 expectedModCount ,记录创建迭代器时候的原始 modCount
    • 当调用集合的 iterator() 函数来创建迭代器的时候,我们把 modCount 值传递给迭代器的 expectedModCount 成员变量
    • 每次调用迭代器上的 hasNext()、next()、currentItem() 函数,我们都会检查集合上的 modCount 是否等于 expectedModCount
    • 若两个值不相同,则说明集合已经改变了,集合发生了增删操作,之前创建的迭代器已经不能正确运行了,再继续使用就会产生不可预期的结果
 
 
 
Spring 源码系列第一章 - Spring 核心组件接口行为型模式之责任链设计模式
Loading...
ITNXD
ITNXD
一个普通的干饭人🍚
最新发布
Java 并发编程
2025-7-31
Spring 源码系列第三章 - 后置 Bean 处理器与 Bean 生命周期
2022-12-25
Spring 源码系列第一章 - Spring 核心组件接口
2022-12-11
Spring 源码系列第二章 - 后置工厂处理器与 Bean 生命周期
2022-12-10
行为型模式之迭代器设计模式
2022-12-2
行为型模式之责任链设计模式
2022-12-1