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

news2024/11/25 16:52:27

在这里插入图片描述
​🌈 个人主页: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;
    }

    @Override
    public boolean hasNext() {
        return index < items.length;
    }

    @Override
    public 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.coloradmin.cn/o/1457121.html

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

相关文章

Matlab|基于支持向量机的电力短期负荷预测【最小二乘、标准粒子群、改进粒子群】

目录 主要内容 部分代码 结果一览 下载链接 主要内容 该程序主要是对电力短期负荷进行预测&#xff0c;采用三种方法&#xff0c;分别是最小二乘支持向量机&#xff08;LSSVM&#xff09;、标准粒子群算法支持向量机和改进粒子群算法支持向量机三种方法对负荷进行…

Eclipse - Colors and Fonts

Eclipse - Colors and Fonts References 编码最好使用等宽字体&#xff0c;Ubuntu 下自带的 Ubuntu Mono 可以使用。更换字体时看到名字里面带有 Mono 的基本都是等宽字体。 Window -> Preferences -> General -> Appearance -> Colors and Fonts -> C/C ->…

Java——IO流

目录 一、IO流的概述 1、IO流的分类 1.1、纯文本文件 2、小结 二、IO流的体系结构 三、字节流 1、FileOutputStream&#xff08;字节输出流&#xff09; 2、FileOutputStream写出数据的细节 3、FileOutputStream写数据的3种方式 3.1、一次写一个字节数据 3.2、一次写…

【网络安全 | 网络协议】一文讲清HTTP协议

HTTP概念简述 HTTP&#xff08;Hypertext Transfer Protocol&#xff09;协议&#xff0c;又称超文本传输协议&#xff0c;用于传输文本、图像、音频、视频以及其他多媒体文件。它是Web应用程序通信的基础&#xff0c;通过HTTP协议&#xff0c;Web浏览器可以向Web服务器发起请…

通俗易懂的L0范数和L1范数及其Python实现

定义 L0 范数&#xff08;L0-Norm&#xff09; L0 范数并不是真正意义上的一个范数&#xff0c;因为它不满足范数的三角不等式性质&#xff0c;但它在数学优化和信号处理等领域有着实际的应用。L0 范数指的是向量中非零元素的个数。它通常用来度量向量的稀疏性。数学上表示为…

合理利用pandas来简化大量请求数据组装工作

工作场景 本次我们开发了一个新功能&#xff0c;为了验证它是否合理&#xff0c;我们需要从线上导出一批真实的用户数据来进行模拟请求&#xff0c;以此来验证功能的完整性。 例如一个很简单的功能&#xff0c;我们是一个对学生成绩进行数据分析的系统&#xff0c;各学校会将…

prometheus+mysql_exporter监控mysql

prometheus+mysql_exporter监控mysql 一.安装mysql 1.下载:wget -i -c http://dev.mysql.com/get/mysql57-community-release-el7-10.noarch.rpm 2.安装客户端:yum -y install mysql57-community-release-el7-10.noarch.rpm 3.安装服务端:yum -y install mysql-community-se…

mysql 2-1

添加数据 方式二 更新数据 删除数据 小结 计算列 数据类型 可选属性 适用场景 如何选择 浮点类型 存在精度问题 定点数介绍 BIT类型 日期与时间类型 YEAR类型 DATA类型 TIME类型 DATATIME TIMESTAMP 文本字符串类型 适用场景 TEXT类型

JavaWeb-JDBC-练习

一、环境准备 1、数据库表 tb_brand 2、实体类 Brand 最后注意使用get、set方法和toString 二、实现功能 1、查询所有数据 2、添加数据 3、根据id修改 4、根据id删除

【类与对象 -2】学习类的6个默认成员函数中的构造函数与析构函数

目录 1.类的6个默认成员函数 2.构造函数 2.1概念 2.2特性 3.析构函数 3.1析构函数的概念 3.2特性 1.类的6个默认成员函数 如果一个类中什么成员都没有&#xff0c;简称为空类。 空类中真的什么都没有吗&#xff1f;并不是&#xff0c;任何类在什么都不写时&#xff0c;…

红队学习笔记Day6 --->干货分享

今天看到这样的一个东西&#xff0c;好好好&#xff0c;有点恐怖&#x1f613;&#x1f613;&#x1f631;&#x1f631;&#x1f631;&#x1f631; 我就想网安是不是也有这种东西&#xff1f; 我来试试 icmp&#xff0c;RDP&#xff0c;arp&#xff0c;dhcp&#xff0c;nat&a…

C语言系列-带有副作用的宏参数#和##命名约定宏替换的规则

&#x1f308;个人主页: 会编辑的果子君 &#x1f4ab;个人格言:“成为自己未来的主人~” 目录 带有副作用的宏参数 宏替换的规则 宏函数的对比 #和## #运算符 ##运算符 命名约定 #undef 带有副作用的宏参数 当宏参数在宏的定义中出现超过一次的时候&#xff0c;如果…

2024/2/19

作业1&#xff1a;使用fread和fwrite完成两个图片文件的拷贝 代码&#xff1a; #include <myhead.h>int main(int argc, const char *argv[]) {FILE *fpNULL;//以只读的形式打开文件if(( fpfopen("./dashuai.bmp","r")) NULL){perror("fopen…

【lesson62】网络通信UdpSocket版

文章目录 UdpSocketUdpServer.hppUdpServer类成员变量解释成员函数解释 UdpServer的实现ServerIinit的实现socketbindhtonsinet_addr具体实现 ServerStart的实现recvfromsendtontohsinet_ntoa具体实现 ~UdpServer函数实现UdpServer.hpp整体完整代码 UdpServer.ccUdpClient.ccTh…

Java学习--黑马SpringBoot3课程个人总结-2024-02-12

1.环境准备 出现报错 Vue 引入路径正确的&#xff0c;但一直报错&#xff1a; Already included file name ‘‘ differs from file name ‘‘ only in casing. 解决方案来自此链接 2.注册界面的搭建 代码如下 <script setup> import { User, Lock } from element-plus/…

【C语言】通讯录(静态版本+动态版本)思路解析+完整源代码

通讯录 由于代码比较长&#xff0c;为了增加可读性&#xff0c;分成了contact.h&#xff0c;contact.c&#xff0c;test.c&#xff0c;分别用来声明函数或者类型&#xff0c;实现函数功能&#xff0c;测试代码 contact.h 我们希望通讯录具有增加联系人&#xff0c;删除联系人…

防火墙之firewalld基础

一、firewalld的简介 firewalld防火墙是Centos7系统默认的防火墙管理工具&#xff0c;取代了之前的iptables防火墙&#xff0c;也是工作在网络层&#xff0c;属于包过滤防火墙。 firewalld和iptables都是用来管理防火墙的工具&#xff08;属于用户态&#xff09;来定义防火墙的…

css pointer-events 多层鼠标点击事件

threejs 无法滑动视角&#xff0c;菜单界面覆盖threejs操作事件。 pointer-events /* Keyword values */ pointer-events: auto; pointer-events: none; pointer-events: visiblePainted; /* SVG only */ pointer-events: visibleFill; /* SVG only */ pointer-events: visib…

web基础及http协议 (二) apache

一、httpd 安装组成 http 服务基于 C/S 结构 1 .常见http 服务器程序 httpd apache&#xff0c;存在C10K&#xff08;10K connections&#xff09;问题 nginx 解决C10K问题lighttpd IIS .asp 应用程序服务器 tomcat .jsp 应用程序服务器 jetty 开源的servlet容器&#xf…

Linux 驱动开发基础知识——LED 模板驱动程序的改造:设备树(十一)

个人名片&#xff1a; &#x1f981;作者简介&#xff1a;学生 &#x1f42f;个人主页&#xff1a;妄北y &#x1f427;个人QQ&#xff1a;2061314755 &#x1f43b;个人邮箱&#xff1a;2061314755qq.com &#x1f989;个人WeChat&#xff1a;Vir2021GKBS &#x1f43c;本文由…