迭代器模式-遍历聚合对象中的元素

news/2025/2/16 1:10:22/

在开发中,我们经常使用到Iterator这个接口,我们很疑惑于这个接口的作用,认为集合已经实现了数据访问的方法,增加Iterator的意义在哪。本文我们将学习迭代器模式,用以探讨Iterator的作用。

1.1 迭代器模式概述

提供一种方法来访问聚合对象,而不用暴露这个对象的内部表示。

聚合对象拥有两个职责:1、存储数据;2、遍历数据。从依赖性来看,前者是聚合对象的基本职责,后者既是可以变化的,又是可分离的。将遍历数据的行为从聚合对象中分离出来,封装在一个被称为迭代器的对象中。由迭代器来提供遍历聚合对象内部数据的行为。

图 迭代器模式结构图

Iterator:抽象迭代器,定义了访问和遍历数据元素的接口。

ConcreteIterator:具体迭代器,实现了抽象迭代器接口,完成对聚合对象的遍历。同时通过游标来记录在聚合对象中所处的当前位置。

Aggregate:抽象聚合类,用于存储和管理元素对象。声明一个creteIterator()方法用于创建一个迭代器对象,充当抽象迭代器工厂角色。

ConcreteAggregate:具体聚合类。实现createIterator()方法,返回一个与该具体聚合类对应的具体迭代器实例。

public interface Iterator<T> {T first();T next();boolean hasNext();T currentItem();}public class ConcreteIterator<T> implements Iterator<T>{private final List<T> list;private int cursor = 0;public ConcreteIterator(ConcreteAggregate<T> list) {this.list = list.getList();}@Overridepublic T first() {return list.get(0);}@Overridepublic T next() {T t = list.get(cursor);cursor++;return t;}@Overridepublic boolean hasNext() {return cursor < list.size();}@Overridepublic T currentItem() {return list.get(cursor);}}public abstract class Aggregate<T> {protected final List<T> list = new ArrayList<>();public abstract Iterator<T> createIterator();public List<T> getList() {return list;}public void addItem(T item) {list.add(item);}}public class ConcreteAggregate<T> extends Aggregate<T>{@Overridepublic Iterator<T> createIterator() {return new ConcreteIterator<>(this);}}public class Client {public static void main(String[] args) {Aggregate<String> aggregate = new ConcreteAggregate<>();aggregate.addItem("你好");aggregate.addItem("JAVA");aggregate.addItem("Hello");aggregate.addItem("world");aggregate.addItem("是谁说的");Iterator<String> iterator = aggregate.createIterator();while (iterator.hasNext()) {System.out.println(iterator.next());}
//        运行结果:
//        你好
//        JAVA
//        Hello
//        world
//        是谁说的}}

1.1.1 使用内部类实现迭代器

具体迭代器类和具体聚合类之间存在双重关系,我们可以使用内部类(JDK中的迭代器类就是通过这种方法来实现的)来实现迭代器,这样可以对外界隐藏具体迭代器的细节。

public class InnerAggregate<T> extends Aggregate<T> {@Overridepublic Iterator<T> createIterator() {return new InnerIterator();}private class InnerIterator implements Iterator<T>{private int cursor = 0;@Overridepublic T first() {return list.get(0);}@Overridepublic T next() {T t = list.get(cursor);cursor++;return t;}@Overridepublic boolean hasNext() {return cursor < list.size();}@Overridepublic T currentItem() {return list.get(cursor);}}}public class Client {public static void main(String[] args) {Aggregate<String> aggregate = new InnerAggregate<>();aggregate.addItem("躺平");aggregate.addItem("努力");Iterator<String> iterator = aggregate.createIterator();while (iterator.hasNext())System.out.println(iterator.next());
//        运行结果:
//        躺平
//        努力}}

2 JDK Collection的迭代器

Java提供了内置迭代器,像常用的List聚合接口,其继承了Collection接口。

图 ArrayList继承类图

图 Iterable与Collection 接口声明方法

ArrayList类使用了内部类Itr来实现内部迭代器。

图 ArrayList 的内部迭代器

图 ArrayList内部迭代器的继承类图

2.1 迭代器与Foreach

Java SE5引入了Iterable接口,该接口被foreach用来在序列中移动。(Collection继承了Iterable接口)

原理:foreach语句最终被编程器转换成对iterator.next()和iterator.hasNext()方法的调用。JDK屏蔽了这些实现细节。

图 foreach Java源代码与编译后的class对比图

3 优缺点

优点:

  1. 支持以不同的方式遍历一个聚合对象,只需用一个不同的迭代器替换原有迭代器即可改变遍历算法。
  2. 简化了聚合类,聚合对象中不需要再自行提供数据遍历方法。将聚合对象的访问与内部数据的存储分离,使得访问聚合对象无须了解其内部实现细节。

缺点:

1)增加了类的个数,设计难度较大,需充分考虑到系统将来的扩展。

4 适用场景

  1. 需要为一个聚合对象提供多种遍历方式。
  2. 访问一个聚合对象的内容而无须暴露它的内部表示。

http://www.ppmy.cn/news/1016576.html

相关文章

Android T 窗口层级相关的类(更新中)

窗口在App端是以PhoneWindow的形式存在&#xff0c;承载了一个Activity的View层级结构。这里我们探讨一下WMS端窗口的形式。 窗口容器类 —— WindowContainer类 /*** Defines common functionality for classes that can hold windows directly or through their* children …

RISC-V云测平台:Compiling The Fedora Linux Kernel Natively on RISC-V

注释&#xff1a;编译Fedora&#xff0c;HS-2 64核RISC-V服务器比Ryzen5700x快两倍&#xff01; --- 以下是blog 正文 --- # Compiling The Fedora Linux Kernel Natively on RISC-V ## Fedora RISC-V Support There is ongoing work to Fedora to support RISC-V hardwar…

外卖项目,登录设计,nginx反向代理,MD5明文加密

.gitignore文件里的东西是进行排除&#xff0c;不用git进行管理。登录设计&#xff0c; controller 接收并封装参数调用service方法查询数据库封装结果并响应 登录成功后&#xff0c;生成jwt令牌 Service层 调用mapper查询数据库密码比对返回结果Mapper 编写sql语句为什么前端不…

配置nginx负载均衡

搭建负载均衡服务的需求如下&#xff1a; 1 .把单台计算机无法承受的大规模并发访问或数据流量分担到多台节点设备上&#xff0c;分别进行处理&#xff0c;减少用户等待响应的时间&#xff0c;提升用户体验。 2. 单个重负载的运算分担到多台节点设备上做并行处理&#xff0c;每…

pyqt5 编写一段自定义信号和槽的示例。

使用 PyQt5 创建自定义信号和槽时&#xff0c;通常需要创建一个继承自 QObject 的类来作为信号的源。以下是一个简单的示例&#xff0c;演示了如何创建自定义信号和槽&#xff1a; import sys from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot from PyQt5.QtWidgets i…

SpringBoot集成websocket(3)|(websocket调用websocket采用回调方式实现数据互传)

SpringBoot集成websocket&#xff08;3&#xff09;|&#xff08;websocket调用websocket采用回调方式实现数据互传&#xff09; 文章目录 SpringBoot集成websocket&#xff08;3&#xff09;|&#xff08;websocket调用websocket采用回调方式实现数据互传&#xff09;[TOC] 前…

ffplay数据结构分析(一)

本文为相关课程的学习记录&#xff0c;相关分析均来源于课程的讲解&#xff0c;主要学习音视频相关的操作&#xff0c;对字幕的处理不做分析 下面我们对ffplay的相关数据结构进行分析&#xff0c;本章主要是对PacketQueue的讲解 struct MyAVPacketList和PacketQueue队列 ffp…

【实战】 九、深入React 状态管理与Redux机制(五) —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(二十)

文章目录 一、项目起航&#xff1a;项目初始化与配置二、React 与 Hook 应用&#xff1a;实现项目列表三、TS 应用&#xff1a;JS神助攻 - 强类型四、JWT、用户认证与异步请求五、CSS 其实很简单 - 用 CSS-in-JS 添加样式六、用户体验优化 - 加载中和错误状态处理七、Hook&…