十四、迭代器模式

文章目录

  • 1 基本介绍
  • 2 案例
    • 2.1 Aggregate 接口
    • 2.2 Iterator 接口
    • 2.3 MyArray 类
    • 2.4 MyArrayIterator 类
    • 2.5 Client 类
    • 2.6 Client 类的运行结果
    • 2.7 总结
  • 3 各角色之间的关系
    • 3.1 角色
      • 3.1.1 Aggregate ( 集合 )
      • 3.1.2 Iterator ( 迭代器 )
      • 3.1.3 ConcreteAggregate ( 具体的集合 )
      • 3.1.4 ConcreteIterator ( 具体的迭代器 )
      • 3.1.4 Client ( 客户端 )
    • 3.2 类图
  • 4 注意事项
  • 5 在源码中的使用
  • 6 优缺点
  • 7 适用场景
  • 8 总结


1 基本介绍

迭代器模式(Iterator Pattern)是一种 行为型 设计模式,它 提供了一种方法来按照某种顺序访问集合中的各个元素而不需要暴露其内部表示

2 案例

本案例实现了一个自定义的 MyArray 类,它可以存放指定数量的 Object 类型的对象,然后通过 MyArrayIterator 类的方法来获取并使用其中储存的元素。

2.1 Aggregate 接口

public interface Aggregate { // 集合接口boolean isEmpty(); // 检查集合是否为空boolean isFull(); // 检查集合是否已满Iterator iterator(); // 返回用于遍历集合的迭代器boolean add(Object obj); // 添加新元素,如果集合已满,则添加失败;否则添加成功int size(); // 返回集合中的元素个数
}

2.2 Iterator 接口

public interface Iterator { // 迭代器接口boolean hasNext(); // 判断是否存在下一个元素Object next(); // 获取下一个元素,同时将迭代器移动到下一个元素的位置
}

2.3 MyArray 类

public class MyArray implements Aggregate {private Object[] array; // 存放元素的数组private int size; // 当前数组中的元素个数public MyArray(int initSize) {array = new Object[initSize];}@Overridepublic boolean isEmpty() {return size == 0;}@Overridepublic boolean isFull() {return size == array.length;}@Overridepublic Iterator iterator() {return new MyArrayIterator(this);}@Overridepublic boolean add(Object obj) {if (isFull()) {return false;}array[size++] = obj;return true;}@Overridepublic int size() {return size;}// 获取索引为 index 的元素,用于 MyArrayIterator 类的 next(),不应该被外部访问到protected Object get(int index) {return array[index];}
}

2.4 MyArrayIterator 类

public class MyArrayIterator implements Iterator {private MyArray myArray; // 待遍历的集合private int curr; // 当前元素索引,也就是迭代器public MyArrayIterator(MyArray myArray) {this.myArray = myArray;}@Overridepublic boolean hasNext() {return curr < myArray.size();}@Overridepublic Object next() {Object obj = myArray.get(curr); // 获取下一个元素curr++; // 将迭代器移动到下一个元素的位置return obj;}
}

2.5 Client 类

public class Client { // 客户端,测试 MyArray 和 MyArrayIteratorpublic static void main(String[] args) {Aggregate myArray = new MyArray(5);myArray.add("Hello, World!");myArray.add(2.0);myArray.add(3000);myArray.add(true);myArray.add('c');Iterator iterator = myArray.iterator();while (iterator.hasNext()) { // 如果集合中有剩余元素Object curr = iterator.next(); // 获取它System.out.println(curr); // 使用它}}
}

2.6 Client 类的运行结果

Hello, World!
2.0
3000
true
c

2.7 总结

通过 MyArrayIterator 迭代器的 hasNext(), next()Client 客户端无需知道 MyArray 集合的内部实现,只需要会使用这两个方法即可,这就 降低了客户端与集合之间的耦合性增强了集合的扩展性。无论集合怎么变,只要它有对应的迭代器类,就可以使用如下的模版获取并使用集合中的所有元素。

Iterator iterator = ?.iterator(); // ? 代表集合的名称
while (iterator.hasNext()) { // 如果集合中有剩余元素Object curr = iterator.next(); // 获取它// 使用它
}

3 各角色之间的关系

3.1 角色

3.1.1 Aggregate ( 集合 )

该角色负责 定义 创建 Iterator 角色 的方法 和 集合应该具备 的方法。本案例中,Aggregate 接口扮演了该角色。

3.1.2 Iterator ( 迭代器 )

该角色负责 定义 按一定顺序逐个遍历元素的 接口。本案例中,Iterator 接口扮演了该角色。

3.1.3 ConcreteAggregate ( 具体的集合 )

该角色负责 实现 Aggregate 角色所定义的 方法,它可以创建 ConcreteIterator 角色。本案例中,MyArray 类扮演了该角色。

3.1.4 ConcreteIterator ( 具体的迭代器 )

该角色负责 实现 Iterator 角色定义的 方法,用于遍历对应的 ConcreteAggregate 角色。本案例中,MyArrayIterator 类扮演了该角色。

3.1.4 Client ( 客户端 )

该角色负责 使用 Aggregate 和 Iterator 角色实现业务逻辑,同时 创建了 ConcreteAggregate 和 ConcreteIterator 角色的对象。本案例中,Client 类扮演了该角色。

3.2 类图

alt text

4 注意事项

  • 集合:
    • 集合应隐藏内部表示:集合应确保通过迭代器访问其元素时,不暴露其内部数据结构。
    • 集合应有一个创建迭代器的方法:集合应提供一个方法(如 iterator())来创建与之对应的迭代器实例。
  • 迭代器:
    • 明确迭代操作:迭代器接口应该明确定义迭代所需的操作,如 hasNext()(是否有下一个元素)、next()(获取下一个元素)等。
    • 迭代器的状态管理:迭代器需要管理其 遍历状态,如 当前位置是否遍历完所有元素 等。
    • 通过迭代器访问元素客户端 应通过迭代器接口来访问集合中的元素,而不是直接访问集合的内部数据结构。
    • 迭代器的生命周期迭代器的生命周期应与其对应的集合相关联。当集合被销毁或发生结构性变化时,相应的迭代器可能变得无效。
    • 迭代器的有效性检查在使用迭代器之前,应检查其是否有效。尝试使用无效的迭代器进行遍历可能会导致运行时错误。
    • 迭代器的效率:迭代器的实现应 尽可能高效,以减少遍历集合时的性能开销。
    • 迭代器的内存使用:在处理大型数据集时,应注意迭代器模式可能引入的额外内存使用,采取相应的优化措施。

5 在源码中的使用

想必大家应该经常使用 JDK 中的 ArrayList 类,这个类就体现了迭代器模式的思想:

  • Aggregate 角色:List<E> 接口扮演该角色,定义了 Iterator<E> iterator(); 的方法:
    Iterator<E> iterator();
    
  • Iterator 角色:Iterator<E> 接口扮演该角色,定义了 boolean hasNext(); E next(); 这两个方法:
    boolean hasNext();
    E next();
    
  • ConcreteAggregate 角色:ArrayList<E> 类扮演该角色,实现了 Iterator<E> iterator(); 方法:
    public Iterator<E> iterator() {return new Itr();
    }
    transient Object[] elementData; // ArrayList 底层用于储存数据的数组
    
  • ConcreteIterator 角色:ArrayList<E> 类的内部类 Itr 类扮演了该角色,实现了 boolean hasNext(); E next(); 这两个方法:
    int cursor; // 当前元素的索引
    int lastRet = -1; // 最后一次调用 next() 前 cursor 的值
    public boolean hasNext() {return cursor != size;
    }public E next() {checkForComodification(); // 无需关心本方法,本方法与迭代器模式无关int i = cursor;if (i >= size) // 在没有足够的元素时报错throw new NoSuchElementException();// 这里的 ArrayList.this.elementData 是外部类 ArrayList 的一个字段Object[] elementData = ArrayList.this.elementData;if (i >= elementData.length) // 在索引越界时报错throw new ConcurrentModificationException();cursor = i + 1; // 指针指向下一个元素return (E) elementData[lastRet = i]; // 记录 cursor 移动之前的值
    }
    

说明:在 Itr 类中没有发现其聚合了 ArrayList<E> 类的对象,这是因为 Itr 类是 ArrayList<E> 的内部类,直接就可以使用 ArrayList<E> 类的底层数据结构 Object[] elementData

6 优缺点

优点

  • 支持以不同的方式遍历一个聚合对象:迭代器简化了遍历方式,使得一个 ConcreteAggregate 可以通过不同的 ConcreteIterator 来以不同的方式遍历。
  • 简化了集合的接口:由于引入了迭代器,集合不再需要暴露其内部表示和遍历算法,从而简化了集合的接口。
  • 降低了系统的耦合性:迭代器模式使得遍历算法独立于集合,从而解开集合的 管理(增删改)与 遍历 之间的耦合。
  • 提高了代码的复用性:无论集合的内部实现如何变化,迭代器都提供了统一的遍历接口,使得遍历集合的代码复用性很高。
  • 支持“懒加载”:在某些情况下,迭代器可以只加载集合的部分元素,只有在真正需要元素时才加载它,这有助于节省内存和提高效率。

缺点

  • 增加了类的数量:在实现迭代器模式时,需要为每个 ConcreteAggregate 实现一个对应的 ConcreteIterator,这会增加类的数量,使得系统变得更加复杂。
  • 迭代器与集合的耦合:虽然迭代器模式降低了集合的 管理 与 遍历 之间的耦合,但 迭代器本身 与 集合 之间存在一定的耦合关系,如果集合的内部实现发生较大变化,则可能需要修改迭代器的实现。
  • 性能考虑:如果 集合中元素数量很少,或者 遍历操作不频繁,那么使用迭代器模式可能会降低性能,不如让集合直接暴露用于遍历的接口。

7 适用场景

  • 提供统一接口:当 需要为不同的集合(如 数组、链表 等)提供 统一 的遍历方式 时,迭代器模式非常有用。通过迭代器,客户端代码可以不必了解集合的具体实现,只需通过迭代器接口进行遍历。
  • 支持多种遍历方式:对于一个集合,可以通过不同的迭代器实现 提供多种遍历方式(如 正序遍历、倒序遍历 等),从而满足不同的遍历需求。
  • 支持复杂数据结构的遍历对于 树 和 图 等复杂数据结构,迭代器模式提供了简化的遍历接口。通过实现特定的迭代器类,可以轻松地使用 树 或 图 的 深度优先搜索(DFS)或 广度优先搜索(BFS)。
  • 按需加载:在 处理大型数据集或无限数据流 时,迭代器模式支持 按需加载 数据元素。这意味着迭代器可以逐个处理数据项,而无需一次性将所有数据加载到内存中,从而提高了内存利用率和系统的响应速度。例如在处理大型文件时,可以使用迭代器模式逐行读取文件内容,而不是一次性将整个文件加载到内存中。

8 总结

迭代器模式 是一种 行为型 设计模式,它 使集合能够按照某种顺序被客户端遍历而不需要暴露其内部表示,核心思想是 将集合的遍历行为抽象出来,放入一个独立的迭代器类中

本模式将集合的 管理遍历 分离开来,降低了 耦合性,使得遍历集合的代码具有很高的 复用性,而且可以实现 按需加载 的功能,从而节省内存空间。

但是这种模式会 增加类的数量,进而增加 系统复杂度。此外,本模式可能还会 降低性能,这就要求我们在使用本模式前仔细考虑 集合中的元素数量遍历操作的频度 了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/400211.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Luminar Neo for Mac/Win:创新AI图像编辑软件的强大功能

Luminar Neo&#xff0c;这款由Skylum公司倾力打造的图像编辑软件&#xff0c;为Mac和Windows用户带来了前所未有的创作体验与编辑便利。作为一款融合了先进AI技术的图像处理工具&#xff0c;Luminar Neo以其独特的功能和高效的操作流程&#xff0c;成为了摄影师、设计师及摄影…

TPshop商城的保姆教程(Ubuntu)

1.上传TPSHOP源码 选择适合自己的版本下载 TPshop商城源文件下载链接&#xff1a; 百度网盘 请输入提取码 上传tpshop的源码包到特定目录/var/www/html 切换到/var/www/html 目录下 cd /var/www/html修改HTML目录下所有文件权限 chmod -R 777 * 2.打开网址配置 TPshop安…

第九届“创客中国”武汉区域赛正式启幕 灵途科技勇夺前三,晋级决赛!

8月8日&#xff0c;第九届“创客中国”武汉区域赛正式启幕&#xff0c;首场聚焦先进制造领域。灵途科技勇夺先进制造领域专场企业组前三名&#xff0c;成功晋级决赛。 “创客中国”大赛是工业和信息化部组织开展的双创赛事活动&#xff0c;以构建产业链协同发展为出发点&#…

鸿蒙(API 12 Beta3版)【扩展屏投播开发指导】使用投播组件

通过本节开发指导&#xff0c;可在系统镜像投屏后&#xff0c;获取投屏设备信息&#xff0c;实现扩展屏模式的投播&#xff0c;实现双屏协作的能力。 运作机制 虚拟扩展屏 是在系统投屏启动过程中建立的&#xff0c;依据双端协商的投屏视频流的分辨率创建&#xff0c;支持1080…

进程与磁盘管理相关

进程与磁盘管理相关 进程创建&#xff08;或者存在的)的唯一标志》进程控制块 PCB是进程存在的唯一标志&#xff0c;当进程被创建时&#xff0c;操作系统为当前进程创建PCB&#xff0c;当进程结束时&#xff0c;会回收PCB PCB .进程描述信息 。进程控制和管理信息 。资源分…

【Next】初识 Next

概述 在Reactr中创建SSR应用&#xff0c;需要调用 ReactDOM.hydrateRoot 函数&#xff0c;而不是 ReactDOM.createRoot。 createRoot:创建一个Root,接着调用其 render 函数将 App 直接加载到页面上hydrateRoot:创建水合 Root, 是在激活的模式下渲染 App 服务端可用 ReactDOM…

增强现实系列—深入探索ARKit:平面检测、三维模型放置与增强现实交互

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

uniapp自定义navigationBar

最终效果&#xff1a; 一、关闭默认导航栏 pages.json文件中&#xff0c;对单个页面关闭 "navigationStyle": "custom" "pages": [ //pages数组中第一项表示应用启动页&#xff0c;参考&#xff1a;https://uniapp.dcloud.io/collocation/pag…

惊!北京三害、上海四毒、广东五虎,谁才是互联网界的“拼命三郎”?

在互联网江湖中&#xff0c;流传着这样一份神秘的“工作强度排名”&#xff0c;它们以地域为划分&#xff0c;将那些被公认为加班狂魔的互联网大厂归为了“北京三害”、“上海四毒”和“广东五虎”。 这份名单一出&#xff0c;让人不禁哑然失笑&#xff0c;同时也让人深思&…

计算机网络部分基础知识

网络协议的意义 单台主机内部的设备之间需要发送和接收消息&#xff0c;那么和相隔很远的两台主机之间发送消息有什么区别呢&#xff1f;两台主机通过网络发送消息&#xff0c;相当于两个网卡设备之间进行通信&#xff0c;最大的区别在于距离变长了。而距离变长带来的结果就是&…

.NET 处理 WebAPI JSON 返回烦人的null为空

目录 前言 一、分析问题 1、空值的处理 2、默认值的处理 3、示例代码 二、解决问题 1、返回的Json 2、null替换为空 3、解决方案 三、总结 四、最后 前言 项目开发中不管是前台还是后台都会遇到烦人的null&#xff0c;数据库表中字段允许空值&#xff0c;则代码实体…

【Python】Python单元测试

文章目录 01-单元测试基础什么是单元测试常用的文件结构运行单元测试 02. 断言函数03. Test Fixtures什么是Test Fixtures模块级别的Fixtures类级别的Fixtures方法级别的Fixtures 04.Mock 01-单元测试基础 什么是单元测试常用的文件结构编写第一个单元测试运行单元测试 什么是单…

springsecurity的学习(四):实现授权

简介 springsecurity的授权&#xff0c;自定义授权失败的处理&#xff0c;跨域的处理和自定义权限校验方法的介绍 授权 权限系统作用 在后台进行用户权限的判断&#xff0c;判断当前用户是否有相应的权限&#xff0c;必须具有所需的权限才能进行相应的操作&#xff0c;以此…

【运维】JetBrains Gateway (Pycharm) SSH免密连接,改为免密连接

一直要求输入密码&#xff0c;很烦人&#xff1a; 如何免密连接&#xff1f; 1 重新打开gateway&#xff0c;来到这个界面点新建连接&#xff1a; 2 点这里设置&#xff1a; 3 在这一页&#xff0c;你可以改你的所有配置&#xff0c;只要设置为password并且保存密码&…

MySQL第6讲--DQL(数据查询语言)的基本操作之基本和条件查询

文章目录 前言DQL(数据查询语言)基本操作查询操作基本查询示例1&#xff1a;查询表格的name&#xff0c;age&#xff0c;并返回&#xff1b;示例2&#xff1a;查询表格中的所有字段&#xff1b;示例3&#xff1a;查询所有员工的工号并返回&#xff0c;起别名&#xff1b;示例4&…

基于Python的去哪儿网数据采集与分析可视化大屏设计与实现

摘要 本文旨在介绍如何利用Python进行去哪儿网景点数据的采集与分析。通过采集去哪儿网上的景点数据&#xff0c;我们可以获取大量的旅游相关信息&#xff0c;并基于这些数据进行深入分析和洞察&#xff0c;为旅游行业、市场营销策略以及用户个性化推荐等提供支持。 本文将使用…

实现挂机会议

png py文件 import os import pyautogui import time from typing import Callable, Tuple from datetime import datetime import cv2 import schedule#通过图像模板匹配在屏幕上找到指定区域并操作 def imgAutoClick(tempFile: str, whatDo: Callable[[Tuple[int, int, int…

【机器学习】混淆矩阵(Confusion Matrix)

一、混淆矩阵 True Negative (TN)&#xff1a; 真负类&#xff0c;样本的真实类别是负类&#xff0c;并且模型将其识别为负类&#xff0c;cm[0][0]。False Positive (FP)&#xff1a; 假正类&#xff0c;样本的真实类别是负类&#xff0c;但是模型将其识别为正类&#xff0c;cm…

【C语言】常用函数汇总表

目录 1. C语言常用函数汇总表&#xff08;概念功能&#xff09;1.1 输入/输出函数&#xff08;<stdio.h>&#xff09;1.2 字符串操作函数&#xff08;<string.h>&#xff09;1.3 内存管理函数&#xff08;<stdlib.h>&#xff09;1.4 数学函数&#xff08;<…

【原创】java+springboot+mysql学业跟踪指导管理系统设计与实现

个人主页&#xff1a;程序猿小小杨 个人简介&#xff1a;从事开发多年&#xff0c;Java、Php、Python、前端开发均有涉猎 博客内容&#xff1a;Java项目实战、项目演示、技术分享 文末有作者名片&#xff0c;希望和大家一起共同进步&#xff0c;你只管努力&#xff0c;剩下的交…