Java 23 种设计模式:从踩坑到精通 | 番外:迭代器模式 —— 物流运单批量处理实战

📅 发布时间:2026/8/12 9:42:24
Java 23 种设计模式:从踩坑到精通 | 番外:迭代器模式 —— 物流运单批量处理实战 Java 23 种设计模式从踩坑到精通 | 番外迭代器模式 —— 物流运单批量处理实战摘要迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素而又无需暴露该对象的内部表示。它将遍历行为从聚合对象中分离出来封装为独立的迭代器对象让客户端可以用统一的方式遍历不同的集合结构。本文结合物流运单批量处理系统的场景完整展示如何用迭代器模式统一遍历不同类型的运单集合并与 for-each 语法糖和数据库游标深度对比帮你掌握“遍历与数据分离”的设计精髓。️本文阅读地图3 分钟速览为什么不能直接暴露集合的内部结构迭代器核心角色抽象迭代器、具体迭代器、抽象聚合、具体聚合手写运单迭代器统一遍历普通件、加急件、冷链件迭代器 vs for-each语法糖的底层原理面试必问“Iterator和Iterable有什么区别为什么不能在 for-each 中直接删除元素”《Java 23 种设计模式从踩坑到精通》开篇系列介绍与目录 正篇Iterator 迭代器模式 —— 遍历集合为什么不直接暴露内部结构 当前番外 · 迭代器模式 × 物流运单批量处理 返回系列总目录1. 物流运单批量处理的痛点在物流分拣中心每天需要批量处理成千上万张运单——普通件、加急件、冷链件。这些运单可能存储在不同的数据结构中有的用数组、有的用链表、有的用树形结构。如果客户端直接依赖这些底层结构来遍历一旦数据结构发生变化如从数组改为链表所有遍历代码都要修改。更麻烦的是不同类型的运单可能需要不同的遍历方式——普通件按顺序处理、加急件需要优先处理、冷链件需要按温度区间分批处理。如果把这些遍历逻辑都写在聚合类中聚合类会迅速膨胀。迭代器模式的解决思路将遍历行为从聚合对象中剥离封装为独立的迭代器对象。客户端只与迭代器接口交互完全不关心底层是数组还是链表。同一个聚合对象可以提供多种迭代器——正向遍历、反向遍历、条件过滤遍历——聚合类本身保持简洁。1.1 你的场景该不该用迭代器判断标准是 → 用迭代器否 → 用其他方式需要隐藏集合的内部结构不暴露给客户端✅❌需要支持多种遍历方式正向、反向、条件过滤✅❌需要统一不同数据结构的遍历接口✅❌结构简单只需一种遍历方式❌直接用 for-each 即可2. 迭代器模式 UML物流运单批量处理场景3. 完整源码实现3.1 抽象迭代器接口 (Iterator)/** * 抽象迭代器定义遍历集合的统一接口 * param T 集合元素类型 */publicinterfaceIteratorT{booleanhasNext();// 是否还有下一个元素Tnext();// 获取下一个元素voidremove();// 删除当前元素可选操作}白话迭代器必须能回答“还有没有下一个”和“把下一个给我”。remove()是可选操作——不是所有迭代器都需要支持删除。3.2 抽象聚合接口 (Aggregate)/** * 抽象聚合定义创建迭代器的工厂方法 * param T 集合元素类型 */publicinterfaceAggregateT{IteratorTcreateIterator();}白话所有集合都必须能“创建一个迭代器出来”。这就是聚合的唯一职责——工厂方法。3.3 运单实体类 (Waybill)/** * 运单实体类 */publicclassWaybill{privateStringwaybillNo;// 运单号privateStringtype;// 类型普通、加急、冷链privateStringdestination;// 目的地privatedoubleweight;// 重量publicWaybill(StringwaybillNo,Stringtype,Stringdestination,doubleweight){this.waybillNowaybillNo;this.typetype;this.destinationdestination;this.weightweight;}publicStringgetWaybillNo(){returnwaybillNo;}publicStringgetType(){returntype;}publicStringgetDestination(){returndestination;}publicdoublegetWeight(){returnweight;}OverridepublicStringtoString(){returnString.format(运单[%s] %s %s %.1fkg,waybillNo,type,destination,weight);}}白话运单就是被遍历的“元素”——包含运单号、类型、目的地、重量等信息。它不关心自己被怎么遍历只管存数据。3.4 具体聚合运单集合 (WaybillCollection)importjava.util.ArrayList;importjava.util.List;/** * 具体聚合运单集合存储所有待处理的运单 */publicclassWaybillCollectionimplementsAggregateWaybill{privateListWaybillwaybillsnewArrayList();publicvoidadd(Waybillwaybill){waybills.add(waybill);}publicWaybillget(intindex){returnwaybills.get(index);}publicintsize(){returnwaybills.size();}OverridepublicIteratorWaybillcreateIterator(){returnnewWaybillIterator(this);}/** 获取内部列表仅供迭代器使用包私有 */ListWaybillgetWaybills(){returnwaybills;}}白话WaybillCollection就是“聚合”——它只管存运单、提供createIterator()工厂方法。内部用ArrayList存储但客户端永远不知道。3.5 具体迭代器运单迭代器 (WaybillIterator)/** * 具体迭代器运单迭代器负责遍历运单集合 */publicclassWaybillIteratorimplementsIteratorWaybill{privateWaybillCollectioncollection;privateintindex0;// 当前遍历位置游标publicWaybillIterator(WaybillCollectioncollection){this.collectioncollection;}OverridepublicbooleanhasNext(){returnindexcollection.size();}OverridepublicWaybillnext(){if(!hasNext()){thrownewIndexOutOfBoundsException(已遍历完所有运单);}returncollection.get(index);}Overridepublicvoidremove(){if(index0){thrownewIllegalStateException(无法删除尚未调用next());}collection.getWaybills().remove(--index);System.out.println( ️ 已删除当前运单);}}白话迭代器就像一个“游标”用index记录当前读到哪里了。hasNext()检查后面还有没有next()取出当前位置的元素并把游标后移。它是聚合的“内部员工”可以访问聚合的私有数据但对外只暴露三个方法。3.6 客户端测试publicclassClient{publicstaticvoidmain(String[]args){// 1. 创建运单集合聚合对象WaybillCollectioncollectionnewWaybillCollection();// 2. 添加运单数据collection.add(newWaybill(SF20240723001,普通件,北京,2.5));collection.add(newWaybill(SF20240723002,加急件,上海,1.2));collection.add(newWaybill(SF20240723003,冷链件,广州,5.0));collection.add(newWaybill(SF20240723004,普通件,深圳,3.8));System.out.println( 场景物流分拣中心遍历处理运单 \n);// 3. 通过聚合对象创建迭代器客户端不关心内部存储结构IteratorWaybilliteratorcollection.createIterator();// 4. 统一遍历处理intcount1;while(iterator.hasNext()){Waybillwaybilliterator.next();System.out.println( 处理第 count 个运单waybill);// 模拟特殊处理逻辑if(冷链件.equals(waybill.getType())){System.out.println( ❄️ 冷链件特殊处理转入冷藏区);}elseif(加急件.equals(waybill.getType())){System.out.println( ⚡ 加急件特殊处理优先分拣通道);}count;}System.out.println(\n 所有运单处理完毕共计 collection.size() 单 );}}白话客户端只需要拿到迭代器用hasNext()next()的标准写法遍历所有运单。如果将来WaybillCollection内部从ArrayList改为链表客户端代码一行都不用改。4. 运行结果 场景物流分拣中心遍历处理运单 处理第 1 个运单运单[SF20240723001] 普通件 北京 2.5kg 处理第 2 个运单运单[SF20240723002] 加急件 上海 1.2kg ⚡ 加急件特殊处理优先分拣通道 处理第 3 个运单运单[SF20240723003] 冷链件 广州 5.0kg ❄️ 冷链件特殊处理转入冷藏区 处理第 4 个运单运单[SF20240723004] 普通件 深圳 3.8kg 所有运单处理完毕共计 4 单 5. 核心角色回顾角色职责对应代码Iterator定义遍历元素的接口IteratorTConcreteIterator维护遍历位置实现遍历逻辑WaybillIteratorAggregate定义创建迭代器的工厂方法AggregateTConcreteAggregate存储数据创建具体迭代器WaybillCollection6. 迭代器模式 vs for-each 语法糖// for-each 写法语法糖for(Waybillwb:collection){System.out.println(wb);}// 编译后等价代码IteratorWaybillitcollection.iterator();while(it.hasNext()){Waybillwbit.next();System.out.println(wb);}对比项迭代器模式for-each 语法糖本质设计模式手动控制遍历编译器自动展开为迭代器循环删除元素✅ 支持iterator.remove()❌ 直接list.remove()会抛异常灵活度高可自定义遍历逻辑低只能顺序遍历一句话记忆你每天都在用 for-each但它的底层就是迭代器模式。Iterable是“能返回迭代器的对象”Iterator是“迭代器本身”。7. 迭代器模式的优缺点优点缺点封装内部结构客户端统一遍历增加类数量支持多种遍历方式正向/反向/过滤简单集合可能过于复杂符合单一职责聚合存数据迭代器管遍历遍历时修改集合可能抛异常8. 六大设计原则体现原则体现单一职责聚合只存储迭代器只遍历开闭原则新增遍历方式只需增加迭代器子类里氏替换所有迭代器可替换Iterator接口依赖倒置客户端依赖抽象Iterator和Aggregate接口隔离Iterator只有三个方法迪米特法则客户端只与迭代器交互不知聚合内部结构附 迭代器模式 UML源码物流运单批量处理场景startuml title Java 23 种设计模式从踩坑到精通 footer 折哥 | 智能物流与Java实战 1. 全局样式配置 skinparam backgroundColor #FEFEFE skinparam shadowing false skinparam classBorderColor #333333 skinparam classFontColor #1A1A1A skinparam classFontSize 14 skinparam noteFontSize 12 skinparam noteFontColor #555555 skinparam arrowColor #555555 skinparam classBackgroundColor #F9F9F9 skinparam interface { BackgroundColor #E8F5E9 BorderColor #2E7D32 } 2. 抽象迭代器 interface Iterator { hasNext() : boolean next() : Object remove() } note right of Iterator b抽象迭代器/b -- 定义遍历集合的统一接口 封装遍历算法与具体聚合解耦 end note 3. 具体迭代器 class ConcreteIterator implements Iterator { - aggregate : ConcreteAggregate - index : int hasNext() : boolean next() : Object remove() } note right of ConcreteIterator b具体迭代器/b -- 维护当前遍历位置index 持有聚合对象的引用 实现具体的遍历逻辑 end note 4. 抽象聚合 interface Aggregate { createIterator() : Iterator } note right of Aggregate b抽象聚合/b -- 定义创建迭代器的工厂方法 客户端通过此接口获取迭代器 end note 5. 具体聚合 class ConcreteAggregate implements Aggregate { - items : List createIterator() : Iterator add(item) get(int) : Object size() : int } note right of ConcreteAggregate b具体聚合/b -- 存储实际的数据集合 实现创建具体迭代器的方法 end note 6. 关系连线 ConcreteIterator ..| Iterator : 实现 ConcreteAggregate ..| Aggregate : 实现 ConcreteAggregate .. ConcreteIterator : 创建 ConcreteIterator -- ConcreteAggregate : 持有引用 enduml 《Java 23 种设计模式从踩坑到精通》快速导航开篇系列介绍与目录正篇Iterator 迭代器模式—— 遍历集合为什么不直接暴露内部结构当前番外 · 迭代器模式 × 物流运单批量处理你在这里创建型模式汇总结构型模式汇总行为型模式汇总 关注《Java 23 种设计模式从踩坑到精通》用 25 篇文章彻底吃透设计模式。福利预告全系列代码及 UML 源码将在完结时统一打包开放点击「关注」「收藏」第一时间获取。 除了设计模式我也在深挖智能物流实战WMS、托盘调度、机器学习落地。欢迎点击头像看看专栏 《出版社物流WMS智能调度实战》、《电商多平台电子面单对接实战》。技术相通思路可鉴。