探索设计模式的魅力:迭代器模式让你轻松驾驭复杂数据集合

在这里插入图片描述
​🌈 个人主页:danci_
🔥 系列专栏:《设计模式》
💪🏻 制定明确可量化的目标,并且坚持默默的做事。


文章目录

  • 一、💡 引言
  • 二、原理与结构 📚
    • 👥 迭代器模式的关键参与者
    • 📐 类图和组件间的交互
    • 🛠️ 迭代器接口和具体迭代器类的实现案例
  • 三、应用实例 🎩🖋️
    • 🖥️ 数组数据结构的迭代
    • 🌲 树数据结构的迭代
  • 四、优缺点与最佳实践🤖
    • 🌈 优点
    • 💪 缺点
    • 🍀 最佳实践

一、💡 引言

大家好👋!今天我们来探索一个至关重要但又不失优雅的编程模式——迭代器模式!在这个信息爆炸、数据成山的时代,能够高效地遍历和管理数据成为了任何软件设计的命脉。想象一下,你有一个珍藏已久的珍珠项链,每一颗珍珠都独一无二,而你需要一个稳妥的方法来欣赏它们而不弄乱它们的顺序,迭代器模式就是这样一个稳妥的设计手段。📿

在这里插入图片描述

🚀 定义迭代器模式

用来提供一种方法顺序访问一个集合对象中的各个元素,而不需要暴露该对象的内部表示。

就像一个迷宫探险家,在复杂的迷宫通道中逐一探索,步步推进,不会迷失方向也不会重踏旧路。🏃‍♀️
在这里插入图片描述
🎯 迭代器模式的目的和主要解决的问题

现实生活中,我们往往需要一种方法来顺畅地穿梭在各种数据结构内,无论是数组、链表还是树结构。而迭代器模式的引入,就是为了简化这项工作,让开发者不必关心底层的数据结构是如何组织的,只需关注如何取用数据。它解决了数据的获取与表示之间的耦合问题,提升了集合管理的灵活性与可维护性。🔍

在这里插入图片描述
🌟 迭代器模式的重要性

在编程中,迭代器模式是不可或缺的。它不仅让代码更整洁,还增强了其可复用性、扩展性和测试性。通过隔离复杂结构,它实现了对数据的高效管理,并确保在对数据结构做出改变时,不会对整个系统的操作造成影响。正因为如此,我们才能在不破坏封装的情况下遍历数据的元素。这是软件设计中真正的力量。💪

在这里插入图片描述

希望这第一部分的内容为理解和实践迭代器模式打下了扎实的基础。继续关注,下面我们将深入探讨迭代器模式如何应用到具体的编程案例中!别忘了点赞和分享,让更多热爱编程的朋友一起学习成长!💖✨

二、原理与结构 📚

👥 迭代器模式的关键参与者

在这里插入图片描述

迭代器(Iterator):
    它是一个接口或抽象类,声明了用于遍历集合的方法,如 next()、hasNext() 等。

具体迭代器(Concrete Iterator):
    实现迭代器接口的类,负责管理对集合的迭代逻辑。

聚合(Aggregate):
    表示集合的接口或抽象类,声明了创建迭代器对象的方法。

具体聚合(Concrete Aggregate):
    实现聚合接口的类,返回一个具体的迭代器实例,该实例能够遍历聚合对象内部的集合。

通过将遍历逻辑放入迭代器中,聚合本身的设计可以保持简洁,并避免暴露其内部结构。🛡️

📐 类图和组件间的交互

迭代器模式的类图说明了组件之间如何交互:

  • 聚合和具体聚合通过createIterator()方法来关联迭代器。
  • 迭代器被具体迭代器实现,完成对集合的具体遍历。
  • 客户端(Client)通过使用迭代器提供的接口与集合进行交互,而无需了解具体聚合的内部构造

🛠️ 迭代器接口和具体迭代器类的实现案例

假设我们要遍历一个特定的集合,例如一个字符串数组。下面是对迭代器模式的一个简单实现:
迭代器接口(Iterator)

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

具体迭代器(Concrete Iterator)

public class ArrayIterator<T> implements Iterator<T> {private T[] items;private int index = 0;public ArrayIterator(T[] items) {this.items = items;}@Overridepublic boolean hasNext() {return index < items.length;}@Overridepublic T next() {if (!hasNext()) {throw new NoSuchElementException();}return items[index++];}
}

在此示例中,ArrayIterator是一个具体的迭代器,可以遍历任意的T[]数组。客户端代码只需实例化ArrayIterator并调用其方法就可以遍历数组而无需知道数组的内部结构。🚀

三、应用实例 🎩🖋️

迭代器模式主要用于顺序访问集合对象的元素,而无需了解其底层实现。让我们深入探讨迭代器模式的一些实际应用场景,了解它如何简化集合操作并提供优雅的数据遍历方式。

🖥️ 数组数据结构的迭代

数组通常用于存储固定大小的同类型数据集合。但如何高效地访问并遍历这些数据呢?迭代器模式展现了其独到之处。使用迭代器,我们可以遍历数组而无需知道其内部构造。这使得代码更加模块化和可复用,同时也更易于理解和维护。
在这里插入图片描述
实现🖋️
让我们来看具体的实现。首先,定义一个具体的迭代器类,它封装了数组的内部结构,并提供Iterator接口定义的方法。然后,在客户端代码中,我们只需创建该迭代器的实例,并使用while循环和hasNext()方法来迭代数组中的每一个元素。🚀

首先,我们定义一个Iterator接口:

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

然后,我们实现一个具体的ArrayIterator类,该类实现了Iterator接口,并用于遍历整数数组:

public class ArrayIterator implements Iterator<Integer> {  private int[] array;  private int currentIndex;  public ArrayIterator(int[] array) {  this.array = array;  this.currentIndex = 0;  }  @Override  public boolean hasNext() {  return currentIndex < array.length;  }  @Override  public Integer next() {  if (!hasNext()) {  throw new IllegalStateException("No more elements to iterate.");  }  return array[currentIndex++];  }  
}

接下来,我们定义一个Aggregation接口,它声明了一个创建迭代器的方法:

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

然后,我们实现一个具体的IntArray类,该类实现了Aggregation接口,并包含一个整数数组:

public class IntArray implements Aggregation<Integer> {  private int[] array;  public IntArray(int[] array) {  this.array = array;  }  @Override  public Iterator<Integer> createIterator() {  return new ArrayIterator(array);  }  
}

最后,我们可以在客户端代码中使用这些类来遍历数组:

public class Client {  public static void main(String[] args) {  int[] numbers = {1, 2, 3, 4, 5};  IntArray intArray = new IntArray(numbers);  Iterator<Integer> iterator = intArray.createIterator();  while (iterator.hasNext()) {  System.out.println(iterator.next());  }  }  
}

运行上述客户端代码输出数组中的每个元素:

1  
2  
3  
4  
5

这个简单的示例展示了如何使用迭代器模式来遍历数组数据结构。通过定义一个通用的Iterator接口和一个具体的ArrayIterator类,我们可以很容易地扩展这种模式来支持其他类型的聚合对象,如ArrayList、LinkedList等。这种模式的关键在于它将遍历逻辑从聚合对象中分离出来,使得客户端代码可以以一种统一的方式来遍历不同的聚合对象。

🌲 树数据结构的迭代

迭代器模式不仅适用于线性数据结构,如数组和列表,也适用于非线性数据结构,如树。在树结构中,迭代器模式允许我们以一种统一和透明的方式遍历树的节点,而不需要关心树的具体实现细节。

实现遍历一个二叉树
🌳首先,我们定义一个通用的Iterator接口,用于迭代树中的节点:

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

🌳接着,我们定义一个简单的二叉树节点类:

public class TreeNode<T> {  private T data;  private TreeNode<T> left;  private TreeNode<T> right;  public TreeNode(T data) {  this.data = data;  }  public T getData() {  return data;  }  public TreeNode<T> getLeft() {  return left;  }  public void setLeft(TreeNode<T> left) {  this.left = left;  }  public TreeNode<T> getRight() {  return right;  }  public void setRight(TreeNode<T> right) {  this.right = right;  }  
}

🌳然后,我们实现一个具体的TreeIterator,用于遍历二叉树的节点:

public class BinaryTreeIterator<T> implements TreeIterator<T> {  private TreeNode<T> currentNode;  private Stack<TreeNode<T>> stack;  public BinaryTreeIterator(TreeNode<T> root) {  currentNode = root;  stack = new Stack<>();  pushLeftSubtree(root);  }  private void pushLeftSubtree(TreeNode<T> node) {  while (node != null) {  stack.push(node);  node = node.getLeft();  }  }  @Override  public boolean hasNext() {  return !stack.isEmpty();  }  @Override  public T next() {  if (!hasNext()) {  throw new NoSuchElementException("No more elements to iterate.");  }  TreeNode<T> currentNode = stack.pop();  pushLeftSubtree(currentNode.getRight());  return currentNode.getData();  }  
}

在这个迭代器实现中,我们使用了一个栈来辅助遍历。当我们调用next()方法时,我们弹出栈顶的节点,并将其右子树的所有节点压入栈中,以便后续遍历。这样,每次调用next()都会返回下一个要遍历的节点。

🌳最后,我们定义一个简单的二叉树类,并提供一个创建迭代器的方法:

public class BinaryTree<T> {  private TreeNode<T> root;  public void setRoot(TreeNode<T> root) {  this.root = root;  }  public TreeIterator<T> iterator() {  return new BinaryTreeIterator<>(root);  }  
}

🌳现在,客户端代码可以使用这个迭代器来遍历二叉树:

public class Client {  public static void main(String[] args) {  // 构建一个简单的二叉树  TreeNode<Integer> root = new TreeNode<>(1);  TreeNode<Integer> leftChild = new TreeNode<>(2);  TreeNode<Integer> rightChild = new TreeNode<>(3);  root.setLeft(leftChild);  root.setRight(rightChild);  BinaryTree<Integer> tree = new BinaryTree<>();  tree.setRoot(root);  // 使用迭代器遍历二叉树  TreeIterator<Integer> iterator = tree.iterator();  while (iterator.hasNext()) {  System.out.println(iterator.next());  }  }  
}

💡 这个示例展示了如何使用迭代器模式来遍历一个二叉树。通过使用栈来辅助遍历,我们可以很容易地实现一个前序遍历的迭代器。如果需要实现其他类型的遍历(如中序遍历或后序遍历),只需调整pushLeftSubtree方法和next方法的逻辑即可。🐬

四、优缺点与最佳实践🤖

🌈 优点

  • 封装性:迭代器模式允许集合对象保持其内部表示法的私有性,只通过迭代器接口暴露必要的方法。这样,客户端代码不需要了解集合对象的具体实现细节,从而提高了封装性。🌟
  • 简化集合遍历:迭代器提供了一种统一的方式来遍历不同的集合对象,无论它们是列表、数组、树还是图。这大大简化了客户端代码,因为客户端代码不需要为每种类型的集合编写特定的遍历逻辑。🌟
  • 管理复杂性:迭代器模式可以将遍历逻辑从集合对象中分离出来,这有助于降低集合对象的复杂性。同时,通过迭代器,可以更容易地添加新的遍历算法,而不需要修改集合对象的代码。🌟
  • 扩展性:由于迭代器模式遵循开闭原则,因此可以在不修改现有代码的情况下添加新的迭代器,以支持新的遍历方式或集合类型。🌟

💪 缺点

  • 额外开销:使用迭代器模式可能会导致一些额外的内存开销,因为需要创建迭代器对象。虽然这个开销通常是可以接受的,但在某些性能敏感的场景下可能需要考虑。😘
  • 实现复杂性:虽然迭代器模式可以提高代码的可维护性和可扩展性,但它也增加了实现的复杂性。开发者需要为集合对象和迭代器分别实现接口和类,这可能会增加开发和维护的工作量。😘

🍀 最佳实践

  • 遵循接口隔离原则:迭代器接口应该尽量简单,只提供必要的遍历方法。避免在迭代器接口中添加与遍历无关的方法。✨
  • 确保迭代器的状态一致性:迭代器应该能够在任何时候正确地反映集合对象的状态。如果集合对象在迭代过程中被修改,迭代器应该能够处理这种情况,或者至少提供一种机制来通知客户端代码。✨
  • 提供失败安全的迭代器:失败安全的迭代器在迭代过程中不会抛出异常,即使集合对象在迭代过程中被修改。这对于确保客户端代码的健壮性非常有用。✨
  • 考虑性能影响:在实现迭代器时,要注意性能问题。例如,如果迭代器需要频繁地访问集合对象,那么可以考虑使用缓存来减少不必要的访问。✨
  • 文档化迭代器接口:迭代器接口应该被清晰地文档化,以便其他开发者能够理解如何使用它。这包括迭代器接口的方法、返回类型、异常以及任何必要的前置条件和后置条件。✨
  • 测试迭代器:确保对迭代器进行充分的测试,包括正常情况下的遍历和边界条件的测试。此外,还应该测试迭代器与集合对象之间的交互,以确保它们能够正确地协同工作。✨

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

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

相关文章

【二十八】springboot整合logback实现日志管理

本章节是记录logback在springboot项目中的简单使用&#xff0c;本文将会演示如何通过logback将日志记录到日志文件或输出到控制台等管理操作。将会从以下几个方面进行讲解。最后实现将特定级别的特定日志保存到日志文件。 一、依赖 <dependency><groupId>ch.qos.l…

基于python的遥感影像灰色关联矩阵纹理特征计算

遥感影像纹理特征是描述影像中像素间空间关系的统计特征&#xff0c;常用于地物分类、目标识别和变化检测等遥感应用中。常见的纹理特征计算方式包括灰度共生矩阵&#xff08;GLCM&#xff09;、灰度差异矩阵&#xff08;GLDM&#xff09;、灰度不均匀性矩阵&#xff08;GLRLM&…

51_蓝桥杯_led流水灯

一 原理图分析 二 三八译码器工作原理 三八译码器&#xff1a;3个输入控制8路互斥的低电平有效输出。 C B A 输出 0 0 0 Y0 0 0 1 Y1 0 1 0 Y2 0 1 1 Y3 1 0 0 Y4 1 0 1 Y5 1 1 0 Y6 1 1 1 Y7 三 锁存器工作原理 锁存器&#xff1a;当使…

OpenAI 全新发布文生视频模型 Sora,支持 60s 超长长度,有哪些突破?将带来哪些影响?

Sora大模型简介 OpenAI 的官方解释了在视频数据基础上进行大规模训练生成模型的方法。 我们下面会摘取其中的关键部分罗列让大家快速get重点。 喜欢钻研的伙伴可以到官网查看技术报告&#xff1a; https://openai.com/research/video-generation-models-as-world-simulator…

BDD - Python Behave 用户自定义配置文件

BDD - Python Behave 用户自定义配置文件 引言默认 behave.ini 配置文件自定义配置文件json 格式的配置文件ini 格式的配置文件 实例应用项目结构代码BDD/Features/user_data.feature 文件BDD/steps/user_data_steps.py 文件BDD/environment.py 文件默认配置文件 behave.ini自定…

BUGKU-WEB 留言板1

题目描述 题目截图如下&#xff1a; 进入场景看看&#xff1a; 解题思路 之间写过一题类似的&#xff0c;所以这题应该是有什么不同的那就按照之前的思路进行测试试试提示说&#xff1a;需要xss平台接收flag&#xff0c;这个和之前说的提示一样 相关工具 xss平台&#xf…

外包干了2个月,感觉技术明显退步...

先说情况&#xff0c;大专毕业&#xff0c;18年通过校招进入湖南某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试&#xf…

BUGKU-WEB 头等舱

题目描述 题目截图如下&#xff1a; 进入场景看看&#xff1a; 解题思路 先看看源码再看看F12请求和响应 相关工具 略 解题步骤 查看源码&#xff0c;好家伙真的什么也没有 2. 看看F12请求和响应&#xff0c;找到了 得到Flag flag{a49c7aba1014c3673ec9982946d0545a…

鸿蒙新手入门-环境准备问题解析

Node.js版本与API配套关系 由于SDK的部分工具依赖Node.js运行时&#xff0c;推荐使用配套API版本的Node.js&#xff0c;保证工程的兼容性。 匹配关系见下表&#xff1a; API LevelNode.js支持范围API Level≤914.x&#xff08;≥14.19.1&#xff09;、16.xAPI Level>914.…

移动端App自动化之触屏操作自动化

工作中我们经常需要对应用的页面进行手势操作&#xff0c;比如滑动、长按、拖动等&#xff0c;AppiumDriver 为我们提供一个模拟手势操作的辅助类 TouchAction&#xff0c;可以通过它对手机屏幕进行手势操作。 具体用法参见链接&#xff1a;chromedriver下载地址与webview自动…

【开源】JAVA+Vue.js实现农村物流配送系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统登录、注册界面2.2 系统功能2.2.1 快递信息管理&#xff1a;2.2.2 位置信息管理&#xff1a;2.2.3 配送人员分配&#xff1a;2.2.4 路线规划&#xff1a;2.2.5 个人中心&#xff1a;2.2.6 退换快递处理&#xff1a;…

docker (七)-部署容器

实战开始&#xff1a; 1 docker 部署 kafka 集群&#xff0c;并验证 参考 Docker搭建Kafka集群 优秀文档 2 docker 部署 mysql 参考上一篇docker(六) 3.docker 部署 zabbix 参考 docker部署zabbix 优秀文档 BUG&#xff1a;根据这篇文章部署后&#xff0c;发现zabbix-s…

春节专题|产业7问:区块链厂商的现在和未来——混合技术厂商

2023转瞬即逝&#xff0c;不同于加密领域沉寂一整年后在年末集中爆发&#xff0c;对于我国的区块链厂商而言&#xff0c;稳中求胜才是关键词&#xff0c;在平稳发展的基调下&#xff0c;产业洗牌也悄无声息的到来。 从产业总体而言&#xff0c;在经过了接近3年的快速发展后&…

MySQL-锁(LOCK)

文章目录 1. 锁是什么&#xff1f;2. 全局锁2.1 相关语法2.2 特点 3. 表级锁3.1 表锁3.1.1 共享读锁&#xff08;S&#xff09;3.1.2 排它写锁&#xff08;X&#xff09; 3.2 元数据锁&#xff08;MDL&#xff09;3.2 意向锁&#xff08;IS、IX&#xff09; 4. 行级锁4.1 行锁 …

基于SpringBoot的药品管理系统

基于SpringBoot的药品管理系统的设计与实现~ 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBootMyBatis工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 主页 药品详情 个人中心 员工界面 管理员界面 摘要 随着医疗技术的不断发展和人们健…

鸿蒙应用模型开发-更新SDK后报错解决

更新SDK后提示 “ohos.application.Ability”/“ohos.application.AbilityStage”等模块找不到或者无相关类型声明 问题现象 更新SDK后报错“Cannot find module ‘ohos.application.AbilityStage’ or its corresponding type declarations”&#xff0c;“Cannot find modu…

有什么办法解决SQL注入问题

随着互联网的普及和数字化进程的加速&#xff0c;Web攻击已经成为网络安全领域的一大威胁。Web攻击不仅可能导致个人隐私泄露、财产损失&#xff0c;还可能对企业和国家的安全造成严重影响。下面德迅云安全就分享一种常见的web攻击方式-SQL注入&#xff0c;了解下什么是SQL注入…

五分钟快速了解软件测试是干什么的

软件测试是互联网技术中一门重要的学科&#xff0c;它是软件生命周期中不可或缺的一个环节&#xff0c;担负着把控、监督软件的质量的重任。 目前&#xff0c;软件测试工程师缺口达30万&#xff0c;其中在我国大中型发达城市的人才需求就突破20万&#xff0c;并以每年20%的速度…

使用傅里叶实现100倍的压缩效果(附Python源码)

傅里叶变换&#xff08;Fourier Transform&#xff09;是一种将一个函数&#xff08;在时间或空间域&#xff09;转换为另一个函数&#xff08;在频率域&#xff09;的数学变换方法。它在信号处理、图像处理、通信等领域有广泛应用。 实现过程 将傅里叶系数核心的1%保留&…

Gin框架: HTML模板渲染之配置与语法详解

Gin的HTML模板配置 1 &#xff09;单一目录的配置 配置模板目录&#xff0c;在与main.go同级下, 新建目录&#xff0c;下面二选一&#xff0c;仅作举例, 这里选择 tpls templatestpls 在 tpls 目录下新建 news.html <!-- 最简单的 --> <h1>News Page</h1>&l…