设计模式——迭代器设计模式(行为型)

摘要

本文详细介绍了迭代器设计模式,这是一种行为型设计模式,用于顺序访问集合对象中的元素,同时隐藏集合的内部结构。文章首先定义了迭代器设计模式并阐述了其核心角色,包括迭代器接口、具体迭代器、容器接口和具体容器。接着,文章通过 Java 标准库中的 Iterator 接口为例,展示了迭代器设计模式的结构和实现方式。此外,文章还探讨了迭代器设计模式的适用场景,包括适合和不适合使用该模式的情况,并通过金融风控的实战示例,展示了如何将迭代器设计模式与其他设计模式(如责任链模式、策略模式等)结合使用。最后,文章总结了迭代器设计模式与其他设计模式的组合使用方式。

1. 迭代器设计模式定义

迭代器设计模式(Iterator Pattern)是一种行为型设计模式,用于顺序访问一个集合对象中的元素,而又不暴露该对象的内部表示结构

1.1. 🔹 核心角色:

角色

说明

Iterator(迭代器接口)

定义访问和遍历元素的接口,如 hasNext()next()

ConcreteIterator(具体迭代器)

实现 Iterator接口,维护当前遍历位置。

Aggregate(容器接口)

定义创建迭代器对象的方法。

ConcreteAggregate(具体容器)

实现 Aggregate接口,返回该容器的迭代器。

Java 标准库中广泛使用了该模式,例如 java.util.Iterator 接口就是该模式的典型实现。

List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {System.out.println(iterator.next());
}

2. 迭代器设计模式结构

  1. 迭代器 (Iterator) 接口声明了遍历集合所需的操作: 获取下一个元素、 获取当前位置和重新开始迭代等。
  2. 具体迭代器 (Concrete Iterators) 实现遍历集合的一种特定算法。 迭代器对象必须跟踪自身遍历的进度。 这使得多个迭代器可以相互独立地遍历同一集合。
  3. 集合 (Collection) 接口声明一个或多个方法来获取与集合兼容的迭代器。 请注意, 返回方法的类型必须被声明为迭代器接口, 因此具体集合可以返回各种不同种类的迭代器。
  4. 具体集合 (Concrete Collections) 会在客户端请求迭代器时返回一个特定的具体迭代器类实体。 你可能会琢磨, 剩下的集合代码在什么地方呢? 不用担心, 它也会在同一个类中。 只是这些细节对于实际模式来说并不重要, 所以我们将其省略了而已。
  5. 客户端 (Client) 通过集合和迭代器的接口与两者进行交互。 这样一来客户端无需与具体类进行耦合, 允许同一客户端代码使用各种不同的集合和迭代器。客户端通常不会自行创建迭代器, 而是会从集合中获取。 但在特定情况下, 客户端可以直接创建一个迭代器 (例如当客户端需要自定义特殊迭代器时)。

2.1. 迭代器类图

2.2. 迭代器时序图

3. 迭代器设计模式实现方式

迭代器设计模式的实现方式主要包括自定义以下四个关键角色:容器接口、具体容器、迭代器接口、具体迭代器。下面是标准的实现步骤(以 Java 为例)。

3.1. 🔹 定义迭代器接口 Iterator

public interface Iterator<T> {boolean hasNext();T next();
}

3.2. 🔹 定义聚合容器接口 Aggregate

public interface Aggregate<T> {Iterator<T> createIterator();
}

3.3. 🔹 实现具体容器 ConcreteAggregate

public class ConcreteAggregate<T> implements Aggregate<T> {private List<T> items = new ArrayList<>();public void add(T item) {items.add(item);}public T get(int index) {return items.get(index);}public int size() {return items.size();}@Overridepublic Iterator<T> createIterator() {return new ConcreteIterator<>(this);}
}

3.4. 🔹 实现具体迭代器 ConcreteIterator

public class ConcreteIterator<T> implements Iterator<T> {private ConcreteAggregate<T> aggregate;private int currentIndex = 0;public ConcreteIterator(ConcreteAggregate<T> aggregate) {this.aggregate = aggregate;}@Overridepublic boolean hasNext() {return currentIndex < aggregate.size();}@Overridepublic T next() {return aggregate.get(currentIndex++);}
}

3.5. 🔹 使用示例

public class Main {public static void main(String[] args) {ConcreteAggregate<String> container = new ConcreteAggregate<>();container.add("A");container.add("B");container.add("C");Iterator<String> iterator = container.createIterator();while (iterator.hasNext()) {System.out.println(iterator.next());}}
}

3.6. ✅ 迭代器示例总结

组件

作用

Iterator 接口

提供统一遍历接口

ConcreteIterator

维护当前索引、实现遍历逻辑

Aggregate接口

提供创建迭代器方法

ConcreteAggregate

存储数据集合,并生成迭代器

4. 迭代器设计模式适合场景

迭代器设计模式的核心目的是提供统一的遍历接口,屏蔽容器内部的数据结构差异。下面是它适合与不适合的场景分析:

4.1. ✅ 适合使用迭代器设计模式的场景

场景

说明

容器类集合遍历

当你希望对集合(数组、列表、树、图等)进行遍历,不暴露其内部结构。

多种容器结构共用遍历方式

例如支持 ListSetMap、自定义集合类都实现一个标准的迭代器接口,便于切换。

需要多种遍历方式

如顺序、逆序、跳跃等不同的遍历策略,可以封装成不同的迭代器类。

自定义复杂聚合对象遍历

比如订单->商品->商品属性 这种层级结构,可以通过迭代器隐藏细节,统一接口。

希望解耦容器与遍历逻辑

把“遍历逻辑”从容器中抽离出来,符合单一职责、开闭原则。

支持多并发遍历操作

每个迭代器对象互不干扰,可以实现并发读操作。

4.2. ❌ 不适合使用迭代器设计模式的场景

场景

原因

集合结构非常简单,且不会改变

比如只有 1~2 个元素,直接使用 for-each 更高效,没必要引入额外迭代器类。

对遍历性能要求极高的系统(高频大数据处理)

自定义迭代器层级增加方法调用,可能影响性能,如在实时交易撮合、低延迟系统中。

对象间耦合必须最小,不能增加接口依赖

引入 Iterator接口会额外增加模块之间依赖,不符合某些架构设计原则。

需要对遍历过程进行复杂控制(如跳转、回溯)

此时可能更适合状态机模式或访问者模式,对每一步状态进行更复杂管理。

遍历逻辑需要携带大量上下文或中间状态

简单的迭代器不适合包含太多状态持久性,需要扩展为上下文感知处理器模式。

4.3. ✅ 举个金融风控例子

适合:遍历用户的多个信用卡账户,统一处理风控评分。

for (Account account : userAccountIterator) {scoreService.evaluate(account);
}

不适合:实时交易撮合引擎中,大量订单队列需要毫秒级处理,使用数组/队列遍历更高效,不宜引入自定义迭代器。

5. 迭代器设计模式实战示例

下面是一个在金融风控场景下,使用迭代器设计模式 + Spring 注解注入方式 实现的示例,适合处理多个风控规则依次执行的业务逻辑。

5.1. 🎯 场景描述

对信贷申请进行风控判断。每个申请会通过一系列规则(如黑名单、年龄检查、信用分检查),每条规则是一个策略,同时这些策略按顺序组成一个责任链。为了支持动态控制规则顺序,还使用迭代器遍历规则链。

5.2. ☕️ 项目结构

com.example.risk
├── RiskRule.java         # 策略接口
├── AbstractRiskRule.java # 模板实现
├── BlackListRule.java    # 黑名单规则
├── AgeLimitRule.java     # 年龄限制规则
├── CreditScoreRule.java  # 信用分规则
├── RuleChainContext.java # 责任链 + 迭代器控制
├── RiskRequest.java      # 入参
├── RiskResponse.java     # 出参
├── RuleConfig.java       # 自动注入规则列表
└── RiskService.java      # 风控服务入口

5.3. 风控请求/响应对象

@Data
public class RiskRequest {private String userId;private int age;private int creditScore;private boolean inBlackList;
}@Data
public class RiskResponse {private boolean passed = true;private String failedReason;
}

5.4. 策略接口和抽象类(策略 + 模板)

public interface RiskRule {boolean evaluate(RiskRequest request, RiskResponse response);String getName();
}public abstract class AbstractRiskRule implements RiskRule {@Overridepublic boolean evaluate(RiskRequest request, RiskResponse response) {if (!doEvaluate(request)) {response.setPassed(false);response.setFailedReason(getName());return false;}return true;}protected abstract boolean doEvaluate(RiskRequest request);
}

5.5. 各种规则实现(策略 + 责任链)

@Component
public class BlackListRule extends AbstractRiskRule {@Overridepublic String getName() {return "黑名单规则";}@Overrideprotected boolean doEvaluate(RiskRequest request) {return !request.isInBlackList();}
}@Component
public class AgeLimitRule extends AbstractRiskRule {@Overridepublic String getName() {return "年龄限制规则";}@Overrideprotected boolean doEvaluate(RiskRequest request) {return request.getAge() >= 18;}
}@Component
public class CreditScoreRule extends AbstractRiskRule {@Overridepublic String getName() {return "信用分规则";}@Overrideprotected boolean doEvaluate(RiskRequest request) {return request.getCreditScore() >= 600;}
}

5.6. RuleChainContext(责任链 + 迭代器)

@Component
public class RuleChainContext {private final List<RiskRule> ruleList;@Autowiredpublic RuleChainContext(List<RiskRule> ruleList) {// 可排序或通过配置动态控制顺序this.ruleList = ruleList;}public RiskResponse process(RiskRequest request) {RiskResponse response = new RiskResponse();Iterator<RiskRule> iterator = ruleList.iterator();while (iterator.hasNext()) {// 迭代器进行遍历RiskRule rule = iterator.next();if (!rule.evaluate(request, response)) {break; // 短路失败}}return response;}
}

5.7. Service调用入口

@Service
public class RiskService {@Autowiredprivate RuleChainContext ruleChainContext;public RiskResponse evaluate(RiskRequest request) {return ruleChainContext.process(request);}
}

5.8. ✅ 使用方式示例

@RestController
@RequestMapping("/risk")
public class RiskController {@Autowiredprivate RiskService riskService;@PostMapping("/check")public RiskResponse check(@RequestBody RiskRequest request) {return riskService.evaluate(request);}
}

5.9. 🧠 总结:设计模式用法回顾

模式

用法说明

策略模式

每一个规则都是一个策略,实现 RiskRule接口

责任链模式

所有规则顺序执行,遇到失败立即终止

迭代器模式

通过 Iterator<RiskRule>遍历所有策略规则

模板方法模式

抽象类定义执行流程,子类重写核心判断逻辑

注解注入

使用 @Component+ @Autowired实现 Spring 自动装配

如需添加动态配置规则链顺序、启用规则开关、分组规则集等功能,可以进一步引入配置中心或数据库控制,支持高扩展。

6. 迭代器设计模式思考

6.1. 🔁 常与迭代器组合使用的设计模式

在实战开发中,迭代器设计模式(Iterator Pattern)通常与以下几种设计模式组合使用,以增强集合结构的灵活性、扩展性、解耦性,尤其在领域模型、规则处理、任务调度等系统中非常常见:

组合模式

搭配原因/典型场景

责任链模式

顺序执行规则或任务链,迭代器负责链路遍历

策略模式

每个元素是一个策略(如规则或算法),通过迭代器遍历并执行

组合模式

组合结构的子元素通过迭代器统一遍历(如树状结构遍历)

模板方法模式

元素结构统一,遍历时调用公共模板方法,保留定制扩展点

观察者模式

遍历一组观察者并触发通知

命令模式

遍历一组命令并逐一执行(或回滚)

装饰器模式

每一层装饰器通过迭代器包装组合

工厂方法模式

工厂批量创建可遍历的对象集合

6.1.1. 与责任链模式

场景:规则引擎、风控审核、流程编排

  • 每个 handler/规则实现 RuleHandler 接口
  • List<RuleHandler> 通过迭代器逐个执行,遇失败中断
for (RuleHandler handler : handlers) {if (!handler.handle(context)) {break;}
}

6.1.2. 与策略模式

场景:算法选择、数据转换器、规则过滤器

  • 每个元素是一个策略类(如计算利息、折扣策略)
  • 迭代器控制策略的执行顺序,支持动态扩展

6.1.3. 与组合模式

场景:菜单树、组织结构、数据表头嵌套结构

  • 组合结构的节点可以通过迭代器实现统一的遍历

6.1.4. 与模板方法模式

场景:日志采集、批量数据导出、统一操作步骤

  • 各子类复用固定遍历结构,通过 doXXX() 定制操作逻辑

6.1.5. 与命令模式

场景:批量命令处理、回滚事务、脚本执行

  • 一组命令对象放入集合,通过迭代器逐个执行或撤销

模式组合

是否常见

典型用途

迭代器 + 责任链

流程控制、规则判断

迭代器 + 策略

动态决策执行、多策略适配

迭代器 + 组合

树形结构统一遍历

迭代器 + 模板方法

标准流程 + 扩展处理

迭代器 + 命令

操作回放、事务控制

迭代器 + 观察者

🟡

通知一组监听者

迭代器 + 单例等

不适合,与集合行为无关

博文参考

  • 迭代器设计模式
  • 设计模式——迭代器设计模式(行为型)

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

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

相关文章

Java8 list集合根据属性分组

在Java8中&#xff0c;可以使用Collectors.groupingBy方法对List集合根据属性进行分组。以下是一个完整的示例&#xff0c;展示如何根据对象的不同属性分组。 根据对象属性分组 假设有一个Student类&#xff0c;包含name、age和grade属性&#xff1a; public class Student …

更新已打包好的 Spring Boot JAR 文件中的 class 文件

# 1. 解压原始 JAR unzip -q original-app.jar -d temp # 2. 替换 class 文件 cp ~/projects/new-classes/*.class temp/BOOT-INF/classes/com/example/ # 3. 保留原始清单 cp temp/META-INF/MANIFEST.MF . # 4. 重新打包 jar -cf0m new-app.jar MANIFEST.MF -C temp/ . # …

《HelloGitHub》第 110 期

兴趣是最好的老师&#xff0c;HelloGitHub 让你对开源感兴趣&#xff01; 简介 HelloGitHub 分享 GitHub 上有趣、入门级的开源项目。 github.com/521xueweihan/HelloGitHub 这里有实战项目、入门教程、黑科技、开源书籍、大厂开源项目等&#xff0c;涵盖多种编程语言 Python、…

当 “欧洲版 Cursor” 遇上安全危机

在 AI 编程助手蓬勃发展的当下&#xff0c;安全问题正成为行业不容忽视的隐忧。近期&#xff0c;AI 编程助手公司 Replit 与号称 “欧洲版 Cursor” 的 Lovable 之间&#xff0c;因安全漏洞问题掀起了一场风波&#xff0c;引发了业界的广泛关注。​ Replit 的员工 Matt Palmer…

centos挂载目录满但实际未满引发系统宕机

测试服务器应用系统突然挂了&#xff0c;经过排查发现是因为磁盘“满了”导致的&#xff0c;使用df -h查看磁盘使用情况/home目录使用率已经到了100%,但使用du -sh /home查看发现实际磁盘使用还不到1G&#xff0c;推测有进程正在写入或占用已删除的大文件&#xff08;Linux 系统…

乾坤qiankun的使用

vue2 为主应用 react 为子应用 在项目中安装乾坤 yarn add qiankun # 或者 npm i qiankun -Svue主应用 在main.js中新增 &#xff08;需要注意的是路由模型为history模式&#xff09; registerMicroApps([{name: reactApp,entry: //localhost:3011,container: #container,/…

PostgreSQL的扩展 auth_delay

PostgreSQL的扩展 auth_delay auth_delay 是 PostgreSQL 提供的一个安全相关扩展&#xff0c;主要用于防止暴力破解攻击。它通过在认证失败后引入人为延迟来增加暴力破解的难度。 一、扩展基础 功能&#xff1a;在认证失败后增加延迟目的&#xff1a;减缓暴力破解和字典攻击…

Web前端为什么要打包?Webpack 和 Vite 如何助力现代开发?

一. 为什么要使用框架库? 1.1 传统网页与现代前端的差异 在最早期的网页开发中,我们只需要写几个.html文件,配上.css和.js文件,浏览器直接加载就能展现页面,每个文件都是独立的静态资源,简单且直观 但现在网站越来越复杂了: 需要用到最新的js语法(比如ES6)使用框架(Vue…

使用pdm+uv替换poetry

用了好几年poetry了&#xff0c;各方面都还挺满意&#xff0c;就是lock实在太慢&#xff1b; 已经试用pdmuv一段时间了&#xff0c;确实是快&#xff0c;也基本能覆盖poetry的功能。 至于为什么用pdmuv&#xff0c;而不是只用uv&#xff0c;原因很多&#xff0c;有兴趣的可以…

java后端生成心电图-jfreechart

用jfreechart生成心电图 先上成功的图片 上代码 1.导入包 implementation org.jfree:jfreechart:1.5.4implementation org.jfree:jcommon:1.0.242.实现代码 对数据进行滤波 转换单位 package com.shinrun.infrastructure.util;import java.util.ArrayList; import java.ut…

微软Build 2025:Copilot Studio升级,解锁多智能体协作未来

微软Build 2025大会圆满落幕&#xff0c;作为年度科技盛会&#xff0c;它一直是开发与AI技术突破性创新的重要展示平台。对于工程师、创作者和领域专家来说&#xff0c;这是了解微软生态未来动向的关键时刻。今年&#xff0c;Microsoft Copilot Studio推出了一系列新功能&#…

LabVIEW杂草识别与精准喷洒

基于LabVIEW构建了一套集成机器视觉、智能决策与精准控制的农业杂草识别系统。通过高分辨率视觉传感器采集作物图像&#xff0c;利用 LabVIEW 的 NI Vision 模块实现图像颜色匹配与特征分析&#xff0c;结合 Arduino 兼容的工业级控制硬件&#xff0c;实现杂草定位与除草剂精准…

使用 Akamai 分布式云与 CDN 保障视频供稿传输安全

作者简介&#xff1a;David Eisenbacher 是 EZDRM 公司的首席执行官兼联合创始人&#xff0c;该公司是首家提供 "DRM 即服务" 的企业。作为 CEO&#xff0c;David 始终秉持为企业确立的使命&#xff1a;为视频服务商提供简洁有效的数字版权管理方案&#xff0c;助力其…

javascript 实战案例 二级联动下拉选框

本案例完全使用原生javascript实现&#xff0c;使用时只需填充platform_list二维数组即可&#xff0c;platform_list填充规则如下&#xff1a; [‘一级选项1’,‘二级选项11’,‘二级选项12’,‘二级选项13’,‘二级选项14’,…], [‘一级选项2’,‘二级选项21’,‘二级选项22’…

Elasticsearch集群最大分片数设置详解:从问题到解决方案

目录 前言 1 问题背景&#xff1a;重启后设置失效 2 核心概念解析 2.1 什么是分片(Shard)&#xff1f; 2.2 cluster.max_shards_per_node的作用 2.3 默认值是多少&#xff1f; 3 参数设置的两种方式 3.2 持久性设置(persistent) 3.2 临时设置(transient) 4 问题解决方…

Redis Sorted Set 深度解析:从原理到实战应用

Redis Sorted Set 深度解析&#xff1a;从原理到实战应用 在 Redis 丰富的数据结构家族中&#xff0c;Sorted Set&#xff08;有序集合&#xff09;凭借独特的设计和强大的功能&#xff0c;成为处理有序数据场景的得力工具。无论是构建实时排行榜&#xff0c;还是实现基于时间的…

Java并发编程:读写锁与普通互斥锁的深度对比

在Java并发编程中&#xff0c;锁是实现线程安全的重要工具。其中&#xff0c;普通互斥锁&#xff08;如synchronized和ReentrantLock&#xff09;和读写锁&#xff08;ReentrantReadWriteLock&#xff09;是两种常用的同步机制。本文将从多个维度深入分析它们的区别、适用场景及…

《云原生安全攻防》-- K8s网络策略:通过NetworkPolicy实现微隔离

默认情况下&#xff0c;K8s集群的网络是没有任何限制的&#xff0c;所有的Pod之间都可以相互访问。这就意味着&#xff0c;一旦攻击者入侵了某个Pod&#xff0c;就能够访问到集群中任意Pod&#xff0c;存在比较大的安全风险。 在本节课程中&#xff0c;我们将详细介绍如何通过N…

Log4j2、Fastjson特征流量分析

文章目录 一、Log4j2流量特征分析1. 漏洞原理简述2. 核心流量特征&#xff08;1&#xff09;请求特征&#xff08;2&#xff09;响应特征&#xff08;3&#xff09;日志特征 3.检测与防御建议 二、fastjson流量特征分析1.漏洞原理简述2.核心流量特征&#xff08;1&#xff09;请…

Java编程之建造者模式

建造者模式&#xff08;Builder Pattern&#xff09;是一种创建型设计模式&#xff0c;它将一个复杂对象的构建与表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。这种模式允许你分步骤构建一个复杂对象&#xff0c;并且可以在构建过程中进行不同的配置。 模式的核…