设计模式学习(18) 23-16 迭代器模式

文章目录

  • 0.个人感悟
  • [1. 概念](#1. 概念)
  • [2. 适配场景](#2. 适配场景)
    • [2.1 适合的场景](#2.1 适合的场景)
    • [2.2 常见场景举例](#2.2 常见场景举例)
  • [3. 实现方法](#3. 实现方法)
    • [3.1 实现思路](#3.1 实现思路)
    • [3.2 UML类图](#3.2 UML类图)
    • [3.3 代码示例](#3.3 代码示例)
      • [3.3.1 类图](#3.3.1 类图)
      • [3.3.2 代码跟踪](#3.3.2 代码跟踪)
  • [4. 优缺点](#4. 优缺点)
    • [4.1 优点](#4.1 优点)
    • [4.2 缺点](#4.2 缺点)

0.个人感悟

  • 迭代器我们并不陌生,java集合操作我们经常使用,只是有for-each、lambda语法糖后我们很少直接使用迭代器,从而忽略其中的原理和思想
  • 迭代器模式很能体现解耦的一些思路:职责分离,聚合的数据和迭代操作分离;面向接口,聚合、迭代器都定义成接口;封装,只关注统一访问,不关注内部实现
  • java集合是经典的设计,大家感兴趣可以了解下。我也计划后面专门总结jdk代码实现

1. 概念

英文定义 (《设计模式:可复用面向对象软件的基础》)

Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.

中文翻译

提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。

理解

  • 分离了集合对象的遍历行为,抽象出一个迭代器来负责遍历
  • 简化了聚合对象的接口,客户端只需要知道迭代器接口
  • 可以在不修改聚合对象的前提下,增加新的遍历方式
  • 为不同的聚合结构提供统一的遍历接口

2. 适配场景

2.1 适合的场景

  1. 遍历复杂数据结构:需要遍历复杂聚合对象,且不希望暴露其内部结构
  2. 统一遍历接口:为不同的聚合结构提供统一的遍历方式
  3. 支持多种遍历方式:聚合对象需要支持多种遍历方式(正序、逆序、按条件过滤等)

2.2 常见场景举例

  1. Java集合框架:List、Set、Map等集合的迭代器
  2. 数据库查询结果集:遍历数据库查询返回的多条记录
  3. 文件系统遍历:遍历目录树中的文件
  4. 社交网络关系遍历:遍历用户的好友、关注者等关系
  5. 菜单系统:遍历餐厅菜单中的菜品项
  6. XML/JSON解析:遍历解析树中的节点

3. 实现方法

3.1 实现思路

  1. 定义迭代器接口 :声明遍历集合元素所需的方法,如hasNext()next()
  2. 实现具体迭代器:为特定聚合对象实现具体的迭代器,管理遍历过程中的当前位置
  3. 定义聚合接口 :声明创建迭代器对象的方法,通常为iterator()createIterator()
  4. 实现具体聚合类:实现聚合接口,返回与自身对应的具体迭代器实例,通常持有集合
  5. 客户端使用迭代器:客户端通过迭代器接口遍历聚合对象,不直接操作聚合内部结构

3.2 UML类图


角色说明:

  • Iterator(迭代器接口):定义访问和遍历元素的接口
  • ConcreteIterator(具体迭代器):实现迭代器接口,记录遍历中的当前位置
  • Aggregate(聚合接口):定义创建迭代器对象的接口
  • ConcreteAggregate(具体聚合):实现聚合接口,返回具体迭代器的实例

3.3 代码示例

珠玉在前,就来看看ArraayList的相关实现

3.3.1 类图

跟踪代码,不然发现,类图:

3.3.2 代码跟踪

迭代器接口: 定义了标准的迭代器操作

java 复制代码
public interface Iterator<E> {
    boolean hasNext();
    E next();
    default void remove() {
        throw new UnsupportedOperationException("remove");
    }  
}

聚合接口:

java 复制代码
public interface Iterable<T> {
    Iterator<T> iterator();
}

具体聚合和具体迭代器:ArrayList:实现,我们知道它的底层是Object[]; 具体迭代器是一个内部类Itr 。简化版代码如下

java 复制代码
public class ArrayList<E> implements Iterable<E> {
    // object数组
    private Object[] elementData;
    private int size;
    
    // ... ArrayList的其他方法
    
    // 实现Iterable接口,返回迭代器
    @Override
    public Iterator<E> iterator() {
        return new Itr();
    }
    
    // 具体迭代器(内部类)
    private class Itr implements Iterator<E> {
        int cursor;       // 下一个元素的索引
        int lastRet = -1; // 上一个返回元素的索引
        
        Itr() {}
        
        @Override
        public boolean hasNext() {
            return cursor != size;
        }
        
        @SuppressWarnings("unchecked")
        @Override
        public E next() {
            if (cursor >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            E nextElement = (E) elementData[cursor];
            lastRet = cursor;
            cursor++;
            return nextElement;
        }
        
        @Override
        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            ArrayList.this.remove(lastRet);
            cursor = lastRet;
            lastRet = -1;
        }
    }
}

客户端使用:

java 复制代码
public class Client {  
    static void main() {  
        // main  
        List<String> list = new ArrayList<>();  
        list.add("1");  
        list.add("2");  
        list.add("3");  
        Iterator<String> iterator = list.iterator();  
        while (iterator.hasNext()) {  
            System.out.println(iterator.next());  
        }  
    }  
}

4. 优缺点

4.1 优点

  1. 符合单一职责原则:将遍历行为从聚合对象中分离,使聚合对象只关注数据存储
  2. 符合开闭原则:可以增加新的聚合类和迭代器类而无需修改现有代码
  3. 支持并行遍历:可以在同一个聚合对象上同时进行多个遍历
  4. 简化客户端代码:客户端使用统一的接口遍历不同的聚合结构
  5. 提高复用性:迭代器可以在多个地方复用,不需要重复编写遍历代码

4.2 缺点

  1. 增加系统复杂性:对于简单集合,直接遍历可能更简单
  2. 可能降低性能:迭代器需要维护遍历状态,比直接索引访问稍慢
  3. 访问限制:迭代器通常只提供顺序访问,不支持随机访问
  4. 并发修改问题:在迭代过程中修改集合可能导致异常

参考:

相关推荐
西岸行者3 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意3 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码3 天前
嵌入式学习路线
学习
毛小茛3 天前
计算机系统概论——校验码
学习
babe小鑫3 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms3 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下3 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。3 天前
2026.2.25监控学习
学习
im_AMBER3 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J3 天前
从“Hello World“ 开始 C++
c语言·c++·学习