设计模式学习(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. 并发修改问题:在迭代过程中修改集合可能导致异常

参考:

相关推荐
我即将远走丶或许也能高飞2 小时前
reduxjs/toolkit 的学习使用
前端·javascript·学习·reactjs
进阶小白猿2 小时前
Java技术八股学习Day22
java·开发语言·学习
DXM05212 小时前
Origin 制图全攻略:50+图表类型制作要点与适用场景解析
笔记·学习·arcgis·信息可视化·origin·制图·统计图
im_AMBER2 小时前
Leetcode 104 两两交换链表中的节点
笔记·学习·算法·leetcode
Das12 小时前
【机器学习】07_降维与度量学习
人工智能·学习·机器学习
Miqiuha3 小时前
二次散列学习
学习·算法·哈希算法
嗯嗯=3 小时前
STM32单片机学习篇7
stm32·单片机·学习
flashier3 小时前
LiteOS与SLE多设备数据传输实战
mcu·学习·ws63·hispark·sle
flashier3 小时前
ESP32学习笔记_WiFi(2)——TCP/UDP
笔记·学习·tcp/ip·wifi·esp32