重温设计模式--迭代器模式

ops/2024/12/25 21:37:38/

文章目录

迭代器模式(Iterator Pattern)概述

  1. 定义
    迭代器模式是一种行为型设计模式它提供了一种方法来顺序访问一个聚合对象(如数组、列表、树等各种容器类型的数据结构)中的各个元素,而又无需暴露该聚合对象的内部表示。简单来说,就是将遍历数据结构的操作和数据结构本身分离开来,让遍历的逻辑更加独立和通用。

  2. 作用

    • 解耦数据结构与遍历逻辑:使得数据结构(如容器类)的设计可以专注于存储和管理元素,而不用关心如何遍历这些元素。同时,遍历的逻辑可以独立于具体的数据结构进行修改和扩展,例如,对于不同类型的容器(数组、链表等),可以使用相同的迭代器接口来进行遍历,提高了代码的可维护性和复用性。
    • 支持多种遍历方式:同一个聚合对象可以有多种不同的迭代器实现,以提供不同的遍历顺序或规则。比如对于一个二叉树结构,可以有中序遍历、前序遍历、后序遍历等不同的迭代器,方便根据具体需求来访问数据。
    • 符合开闭原则:当需要对聚合对象添加新的遍历方式或者修改遍历逻辑时,只需要创建新的迭代器类或者修改已有的迭代器类,而不需要改动聚合对象的代码,对扩展开放,对修改关闭。

迭代器模式的结构

  1. 抽象聚合(Aggregate)类
    它是所有聚合对象的抽象,定义了创建迭代器对象的接口,通常会有一个类似createIterator()这样的抽象方法,用于返回对应的迭代器对象,供客户端获取来遍历聚合对象中的元素。

  2. 具体聚合(Concrete Aggregate)类
    实现了抽象聚合类的接口,它内部维护了数据元素的存储结构,并且实现了创建迭代器的方法,返回的是与自身数据结构相匹配的具体迭代器对象,这样客户端就能通过这个迭代器来访问它所包含的元素。

  3. 抽象迭代器(Iterator)类
    定义了遍历聚合对象的接口,通常包含诸如first()(定位到第一个元素)、next()(移动到下一个元素)、isDone()(判断是否遍历完所有元素)、currentItem()(获取当前元素)等抽象方法,这些方法规范了遍历操作的基本行为,所有具体的迭代器都要实现这些方法。

  4. 具体迭代器(Concrete Iterator)类
    实现了抽象迭代器类定义的接口,针对具体的聚合对象的存储结构,实现了具体的遍历逻辑,通过内部指针或索引等方式来跟踪当前遍历的位置,从而正确地实现各个遍历操作方法,使得客户端可以按照期望的方式遍历聚合对象中的元素。

迭代器模式UML图

在这里插入图片描述

C++ 代码示例

以下以一个简单的自定义数组容器为例,来展示迭代器模式的代码实现。

#include <iostream>// 抽象迭代器类
class Iterator
{
public:virtual void first() = 0;virtual void next() = 0;virtual bool isDone() = 0;virtual int currentItem() = 0;virtual ~Iterator() {}
};// 抽象聚合类
class Aggregate
{
public:virtual Iterator* createIterator() = 0;virtual ~Aggregate() {}
};// 具体聚合类:自定义数组容器
class MyArray : public Aggregate 
{
private:int* elements;int size;
public:MyArray(int* arr, int s) : elements(arr), size(s) {}Iterator* createIterator() override{return new ArrayIterator(this);}int getSize(){return size;}int at(int index){return elements[index];}
};// 具体迭代器类:针对自定义数组的迭代器
class ArrayIterator : public Iterator
{
private:MyArray* array;int index;
public:ArrayIterator(MyArray* arr) : array(arr), index(0) {}void first() override{index = 0;}void next() override{index++;}bool isDone() override{return index >= array->getSize();}int currentItem() override{return array->at(index);}
};int main() 
{int arr[] = {1, 2, 3, 4, 5};MyArray myArray(arr, 5);Iterator* it = myArray.createIterator();for (it->first();!it->isDone(); it->next()){std::cout << it->currentItem() << " ";}std::cout << std::endl;delete it;return 0;
}

在上述代码中:

  • Iterator是抽象迭代器类,定义了迭代器的基本操作接口,规范了遍历的通用行为。
  • Aggregate是抽象聚合类,声明了创建迭代器的抽象方法,作为所有聚合对象的抽象基类。
  • MyArray是具体聚合类,它内部持有一个整数数组作为实际存储的数据结构,实现了createIterator方法,返回一个针对自身结构的ArrayIterator对象,以便外部能获取迭代器来遍历数组元素。
  • ArrayIterator是具体迭代器类,它通过维护一个索引变量来跟踪当前遍历的位置,实现了firstnextisDonecurrentItem等方法,按照顺序正确地遍历MyArray中的元素。在main函数中,创建了一个MyArray对象,获取其迭代器并通过循环利用迭代器的方法来遍历数组元素并输出,展示了迭代器模式在自定义数组容器中的简单应用,体现了数据结构与遍历逻辑分离以及通过统一接口进行遍历的特点。

应用场景

  1. 容器类库的实现
    像C++标准模板库(STL)中的各种容器(如vectorlistmap等)都广泛应用了迭代器模式。它们提供了对应的迭代器,使得用户可以方便地遍历容器中的元素,而且不同容器的迭代器遵循统一的接口规范,比如都可以使用begin()end()方法获取迭代器的起始和结束位置,方便了算法函数(如std::for_eachstd::find等)对不同容器元素的操作,提高了代码的通用性和复用性。
  2. 数据库查询结果集遍历
    在数据库编程中,当执行查询语句后会返回一个结果集,这个结果集可以看作是一个聚合对象。使用迭代器模式可以创建相应的迭代器来遍历结果集中的每一条记录(通常包含多个字段的数据),按照一定顺序获取记录中的数据,方便后续的数据处理和展示,而且不同数据库系统的结果集都可以通过实现类似的迭代器接口来提供统一的遍历方式,便于上层应用程序的开发。
  3. 树形结构数据遍历
    对于二叉树、多叉树等树形结构的数据,如文件系统目录树(文件夹可以包含子文件夹和文件,类似树的节点和子节点关系)、组织结构树(部门包含子部门和员工等),可以利用迭代器模式创建不同遍历顺序(如前序、中序、后序遍历二叉树,深度优先或广度优先遍历一般的树形结构)的迭代器,方便按照特定需求访问树中的各个节点元素,进行节点数据的获取、统计等操作。
  4. 游戏地图元素遍历
    在游戏开发中,游戏地图通常由多个地块(如方格、区域等)组成,这些地块可以看作是一个聚合对象。通过迭代器模式,可以创建合适的迭代器来遍历地图上的各个地块,例如查找特定类型的地块(有怪物的地块、有宝藏的地块等)、统计地块数量等,并且如果地图结构发生变化(如增加新区域、改变地块布局等),只需要调整迭代器的实现或者创建新的迭代器,而不需要大规模改动地图本身的管理代码。

由于迭代器模式应用场景太多,而且频次较大,C++ C# Python等语言已经把迭代器模式嵌入到语言中了,不需要用户进行专门的迭代器设计,比如C++ STL list

#include<iostream>
#include<list>
using namespace std;int main()
{list<int> m_list;for(int i=0;i<10;++i){m_list.push_back(i);}list<int>::iterator itr = m_list.begin();for(;itr!=m_list.end(); ++itr){cout<<*itr<<endl;}return 0;
}

http://www.ppmy.cn/ops/144942.html

相关文章

关于uni-forms组件的bug【提交的字段[‘*‘]在数据库中并不存在】

问题&#xff1a;在使用 uni-forms校验的时候&#xff0c;出来的一个问题&#xff0c;这个字段都没有设置校验的规则&#xff0c;不知道什么原因就出现了下图的问题&#xff1a; 解决办法&#xff1a; 在uni-forms-item 添加key 值就解决了 原因不知道&#xff0c;有大佬发现…

​在VMware虚拟机上设置Ubuntu与主机共享文件夹​

‌在VMware虚拟机上设置Ubuntu与主机共享文件夹的步骤如下‌&#xff1a; ‌主机共享文件夹的设置‌&#xff1a;首先&#xff0c;在主机上选择一个磁盘分区创建一个文件夹&#xff0c;并设置其共享属性。右键点击该文件夹&#xff0c;选择“属性”&#xff0c;然后在“共享”选…

基于Spring Boot的远程教育网站

一、系统背景与意义 随着互联网技术的飞速发展和普及&#xff0c;远程教育已成为现代教育体系中的重要组成部分。它打破了时间和空间的限制&#xff0c;让学习者可以随时随地进行学习。基于Spring Boot的远程教育网站正是为了满足这一需求而设计的&#xff0c;它利用互联网技术…

如何详细地遵循RustDesk的步骤来搭建远程访问和自定义服务器?

要详细地遵循RustDesk的步骤来搭建远程访问和自定义服务器&#xff0c;你可以按照以下几个主要步骤进行操作&#xff1a; 下载并安装RustDesk&#xff1a;前往RustDesk的官方网站&#xff08;https://rustdesk.com/&#xff09;下载适用于你的操作系统的安装程序。然后&#xf…

autMan奥特曼机器人-相关命令

基础命令 set autMan adminUsername xxxxxx #设置后台登录的账户名&#xff0c;仅用于后台登陆&#xff0c;对云账号不影响 set autMan adminPassword xxxxxx #设置后台登陆密码&#xff0c;仅用于后台登陆&#xff0c;对云账号不影响 set autMan name 奥特曼 #设置奥特曼机器…

【网络安全】John the Ripper 散列密码,PDF密码

John the Ripper 1. John the Ripper 散列密码 假设我们已经获取到一个数据泄露中包含的散列密码文件 hash1.txt&#xff0c;并需要还原原始密码。步骤如下&#xff1a; 识别散列类型 通过 hash-id.py 工具&#xff0c;我们确认 hash1.txt 的散列类型是 SHA-256。 usermach…

golang LeetCode 热题 100(动态规划)-更新中

爬楼梯 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 示例 1&#xff1a;输入&#xff1a;n 2 输出&#xff1a;2 解释&#xff1a;有两种方法可以爬到楼顶。 1. 1 阶 1 阶 2. 2 阶 示例 2&…

java 大数据开发

在 Java 大数据开发中,涉及的技术非常广泛,涵盖数据存储、分布式计算、流处理、搜索、机器学习等多个方面。以下是一个完整的技术栈指南,涵盖了大数据开发所需的关键技术: 1. 大数据基础框架与平台 大数据的基础平台包括分布式存储、计算框架等,了解这些框架是进行大数据…