当前位置: 首页 > news >正文

【设计模式】行为型设计模式之 迭代器模式

介绍

迭代器模式(Iterator Pattern) 是行为设计模式之一,它提供了一种访问集合对象(如列表、数组或其他集合结构)中元素的方式,而不需要暴露集合的内部结构。迭代器模式定义了一个迭代器接口,该接口负责遍历集合中的元素,这样用户就可以通过迭代器来访问集合的元素,而无需了解集合的具体实现。
一个完整的迭代器模式包含集合和迭代器两部分内容,集合又分为集合接口和实现类、迭代器分为迭代器实现类和接口。
202107-23-iterator-pattern.png

优点

封装性:迭代器将遍历集合的责任封装在迭代器对象中,集合的内部结构对外界是隐藏的。
支持多种遍历:同一个集合可以有多种遍历方式,只需提供不同的迭代器实现即可。
简化集合接口:集合类无需暴露内部结构和遍历算法,使得集合类的设计更加简洁。
迭代期间的修改:某些迭代器设计允许在迭代过程中安全地修改集合,例如Java的Iterator提供了remove()方法。

迭代器遍历集合可能存在的问题

迭代器遍历时删除元素或者增加元素导致不可预期的情况

删除元素:删除了游标及游标前元素,可能导致某个元素遍历不到。删除了游标后的元素则无影响
增加元素:在制定位置添加元素时,如果在游标及游标前增加元素可能导致某个元素被重复遍历,如果在游标后增加元素则不会出现重复遍历的问题。

遍历时遇到集合删除或增加元素的解决方案

程序中不可预期的错误比直接出错更可怕

方案 1 遍历时粗暴地不允许修改集合
方案 2 fast-fail 策略 遍历的过程中一旦发现集合被修改了,则立即抛出异常终止遍历

java 的一些集合就是这么做的,例如 ArrayListLinkedListHashSetHashMap等集合的迭代器。其实现原理就是,在集合中保存一个 modCount 记录集合修改的次数。创建迭代器时会保存当前的修改次数,每次使用迭代器的 hasNext、next、currentItem 等方法时都会检查集合对比迭代器创建时的修改次数是否变化,一旦变化立刻抛出异常。避免产生更大的影响。

方案 3 fail-safe
  • 定义:即使在遍历过程中集合被修改,也不会抛出异常,能够安全地完成遍历过程。这是通过拷贝原集合的数据结构来实现的,因此对原集合的修改不会影响到迭代过程。
  • 实现原理:安全失败的集合通常通过内部维护一个快照或者只读视图来保证迭代过程中数据的一致性,即使原集合发生了改变,迭代器遍历的是快照的数据,因此不会抛出异常。
  • 典型应用CopyOnWriteArrayListCopyOnWriteArraySetConcurrentHashMap的迭代器就采用了安全失败机制。这些集合在修改时,会创建一个新的数据结构来保存修改后的数据,原有数据结构保持不变,从而保证了迭代过程的安全性。

Java 的迭代器类的 Remove 方法原理

  1. Java 的迭代器提供了 remove 方法,但是只能删除游标指向的前一个元素
  2. 每次调用完 next 函数后,能且仅能调用一次 remove 方法多次调用则会直接报错。
  3. Java 的迭代器没有添加元素方法,因为迭代器的主要作用是遍历。
  4. 原理:迭代器有一个成员变量 lastRet 记录了游标元素的前一个元素,通过迭代器删除这个元素时会更新迭代器中的游标和 lastRet 值,将 lastRet 向前移动一个元素,同时将游标指向原本的 lastRet 的位置,这样可以
  5. 保证不会因为删除元素导致某个元素遍历不到

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • LeetCode 算法:合并区间c++
  • 封装了一个简单理解的iOS竖直文字轮播
  • k8s学习--kubernetes服务自动伸缩之水平收缩(pod副本收缩)VPA策略应用案例
  • Wireshark TS | 应用传输丢包问题
  • No ‘ChromeSansMM’ font 错误解决
  • 渗透测试之内核安全系列课程:Rootkit技术初探(一)
  • vue面试题2-根据以下问题回答
  • ChatGP和kimi对比
  • Docker之路(三)docker安装nginx实现对springboot项目的负载均衡
  • Java 程序结构 -- Java 语言的变量、方法、运算符与注释
  • Apache Spark
  • 解释一下I/O多路复用模型?
  • 单元测试覆盖率
  • 如何提高网站访问量?
  • Kafka 详解:全面解析分布式流处理平台
  • 收藏网友的 源程序下载网
  • 2018以太坊智能合约编程语言solidity的最佳IDEs
  • JDK9: 集成 Jshell 和 Maven 项目.
  • Python语法速览与机器学习开发环境搭建
  • RedisSerializer之JdkSerializationRedisSerializer分析
  • SpiderData 2019年2月25日 DApp数据排行榜
  • 编写高质量JavaScript代码之并发
  • 前端性能优化--懒加载和预加载
  • 如何实现 font-size 的响应式
  • 我看到的前端
  • 格斗健身潮牌24KiCK获近千万Pre-A轮融资,用户留存高达9个月 ...
  • ​3ds Max插件CG MAGIC图形板块为您提升线条效率!
  • #【QT 5 调试软件后,发布相关:软件生成exe文件 + 文件打包】
  • #gStore-weekly | gStore最新版本1.0之三角形计数函数的使用
  • #systemverilog# 之 event region 和 timeslot 仿真调度(十)高层次视角看仿真调度事件的发生
  • (C++哈希表01)
  • (k8s)Kubernetes 从0到1容器编排之旅
  • (力扣)循环队列的实现与详解(C语言)
  • (已解决)什么是vue导航守卫
  • .net core 微服务_.NET Core 3.0中用 Code-First 方式创建 gRPC 服务与客户端
  • .Net 执行Linux下多行shell命令方法
  • .Net 转战 Android 4.4 日常笔记(4)--按钮事件和国际化
  • .NET连接MongoDB数据库实例教程
  • .NET企业级应用架构设计系列之应用服务器
  • ;号自动换行
  • @AliasFor注解
  • @Autowired标签与 @Resource标签 的区别
  • @param注解什么意思_9000字,通俗易懂的讲解下Java注解
  • @Transactional 竟也能解决分布式事务?
  • [ SNOI 2013 ] Quare
  • [012-1].第12节:Mysql的配置文件的使用
  • [2019/05/17]解决springboot测试List接口时JSON传参异常
  • [ActionScript][AS3]小小笔记
  • [AIGC] MySQL存储引擎详解
  • [AUTOSAR][诊断管理][ECU][$37] 请求退出传输。终止数据传输的(上传/下载)
  • [BFS广搜]迷阵
  • [bzoj1901]: Zju2112 Dynamic Rankings
  • [EFI]NUC11电脑 Hackintosh 黑苹果efi引导文件
  • [Flutter]设置应用包名、名称、版本号、最低支持版本、Icon、启动页以及环境判断、平台判断和打包
  • [Hibernate] - Fetching strategies