C++设计模式行为模式———迭代器模式

文章目录

  • 一、引言
  • 二、迭代器模式
  • 三、总结

一、引言

迭代器模式是一种行为设计模式, 让你能在不暴露集合底层表现形式 (列表、 栈和树等) 的情况下遍历集合中所有的元素。C++标准库中内置了很多容器并提供了合适的迭代器,尽管我们不需要实现迭代器,但是需要了解迭代器的设计理念。


二、迭代器模式

我们设计一个固定大小数组作为容器,并实现一个迭代器。首先创建一个抽象迭代器:

template<class T>
class myIter{
public:virtual void First() = 0;virtual void Next() = 0;//指向下一个元素virtual bool IsDone() = 0;//是否遍历完virtual T& CurrentItem() = 0;//获取当前的元素virtual ~myIter() {}//作父类时析构函数应该为虚函数
};

上述迭代器仅有四个接口,这4个接口一般被认为是选代器应该实现的最小接口。当然,也可以根据实际需要,增加更多的接口。接着,创建一个抽象容器:

template<class T>
class myContainer{
public:
public:virtual myIter<T>* CreateIterator() = 0;//创建选代器virtual T& getItem(int index) = 0;//获取当前元素virtual int getSize() = 0;//容器中元素数量virtual ~myContainer() {}//作父类时析构函数应该为虚函数
};

从上面的代码中可以看到,为了支持所谓的多态迭代,在抽象容器类模板中定义了一个CreateIterator接口(成员函数),后续在具体的容器子类模板中,会在该接口中运用工厂模式创建相应的选代器。

template<class T>
class myVectorIter :public myIter<T>
{
public:myVectorIter(myContainer<T>*tmpc) :myvector(tmpc){m_current = 0;}virtual void First(){m_current = 0;//容器(数组)中的第一个元素下标为0}	virtual void Next(){m_current++;//下标+1,意味着数组中的下一个元素}virtual bool IsDone(){if (m_current >= myvector->getSize())return true;return false;}virtual T& CurrentItem(){return myvector->getItem(m_current);}
private:myContainer<T>* myvector;int m_current;//记录数组的当前下标(选代器在当前容器中的位置)
};

最后来一个具体的容器:

//具体容器类模板
template<typename T>
class myVector :public myContainer<T>{
public:myVector()//将数组中元素进行初始化{for (int i = 0; i < 10; ++i)m_elem[i] = i;}virtual myIter<T>* CreateIterator(){return new myVectorIter<T>(this);//要考虑在哪里释放的问题}virtual T& getItem(int index){return m_elem[index];}virtual int getSize(){return 10;//为简化代码,返回固定数字}
private://为了简化代码,将容器实现为固定装人10个元素的数组T m_elem[10];
};

在上述代码中,CreateIterator接口使用了工厂模式来创建一个具体的选代器,从而实现了多态选代(这意味着可以增加创建其他选代器的接口来支持不同的送代器,例如,再支持一个反向选代器来从最后一个元素向前遍历等)。

myContainer<int>* pcon = new myVector<int>();
myIter<int>* iter = pcon->CreateIterator();
for (iter->First(); !iter->IsDone(); iter->Next())
{cout << iter->CurrentItem() << endl;
}

代码可以看到,我们的迭代器完成了对容器的遍历。

在这里插入图片描述

迭代器模式一般包含四个角色:

  • 抽象迭代器Iterator):用于定义访问和遍历容器中的元素接口。
  • 具体迭代器ConcreteIterator):实现了抽象迭代器的接口,完成对聚合对象的元素遍历,记录当前元素的位置。
  • 抽象聚合Aggregate):将聚合理解为容器,用于存储和管理元素对象,声明一个CreateIterator方法用于创建一个迭代器对象,充当创建迭代器的工厂角色
  • 具体聚合ConcreteAggregate):实现了抽象的CreateIterator方法以创建相应的迭代器,该方法返回ConcreteAggregate的一个是适当的实例。

迭代器模式结构

在这里插入图片描述

迭代器模式做到了在不暴露内部结构的情况下,让外部代码透明地遍历(访问)其中包含元素的效果,另外值得一提的是,虽然不同的容器内部实现方式不同,但是通过迭代器来访问它们的方式却相同。

引入迭代器设计模式的定义:提供一种方法顺序访问一个聚合对象(容器)中各个元素,而又不暴露该对象的内部表示。

迭代器模式的核心思想就是把容器中对元素访问的代码放人迭代器中实现,与容器本身的功能代码相分离(容器是一个对象,迭代器是另一个对象),从而简化容器的设计。容器和迭代器之间彼此独立,从而使整个系统的设计更加灵活,可以定义不同的迭代器实现不同的遍历策略,例如常规迭代器、反向迭代器、const迭代器等都可以分别实现。


三、总结

当集合背后为复杂的数据结构, 且你希望对客户端隐藏其复杂性时 (出于使用便利性或安全性的考虑), 可以使用迭代器模式。迭代器封装了与复杂数据结构进行交互的细节, 为客户端提供多个访问集合元素的简单方法。 这种方式不仅对客户端来说非常方便, 而且能避免客户端在直接与集合交互时执行错误或有害的操作, 从而起到保护集合的作用。

使用方法:

  1. 声明迭代器接口。 该接口必须提供至少一个方法来获取集合中的下个元素。 但为了使用方便, 你还可以添加一些其他方法, 例如获取前一个元素、 记录当前位置和判断迭代是否已结束。
  2. 声明集合接口并描述一个获取迭代器的方法。 其返回值必须是迭代器接口。 如果你计划拥有多组不同的迭代器, 则可以声明多个类似的方法。
  3. 为希望使用迭代器进行遍历的集合实现具体迭代器类。 迭代器对象必须与单个集合实体链接。 链接关系通常通过迭代器的构造函数建立。
  4. 在你的集合类中实现集合接口。 其主要思想是针对特定集合为客户端代码提供创建迭代器的快捷方式。 集合对象必须将自身传递给迭代器的构造函数来创建两者之间的链接。
  5. 检查客户端代码, 使用迭代器替代所有集合遍历代码。 每当客户端需要遍历集合元素时都会获取一个新的迭代器。

我们可以使用迭代器模式来遍历组合模式。也可以使用工厂方法模式和迭代器来让子类返回不同的迭代器,并使得迭代器与集合相匹配。

身传递给迭代器的构造函数来创建两者之间的链接。
5. 检查客户端代码, 使用迭代器替代所有集合遍历代码。 每当客户端需要遍历集合元素时都会获取一个新的迭代器。

我们可以使用迭代器模式来遍历组合模式。也可以使用工厂方法模式和迭代器来让子类返回不同的迭代器,并使得迭代器与集合相匹配。

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

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

相关文章

常用Adb 命令

# 连接设备 adb connect 192.168.10.125# 断开连接 adb disconnect 192.168.10.125# 查看已连接的设备 adb devices# 安装webview adb install -r "D:\webview\com.google.android.webview_103.0.5060.129-506012903_minAPI23(arm64-v8a,armeabi-v7a)(nodpi)_apkmirror.co…

Redis-08 Redis集群

Redis槽位 Redis分片 Redis集群优势 主要掌握第三种 为什么槽位是16384&#xff1f; 三主三从&#xff1a; 每个主机只能写在自己的槽位 所以登录redis集群记得加参数 -c 比如redis-cli -a dc123 -p 6380 -c 加了 -c 相当于会进行路由转发&#xff0c;不属于自己槽位的…

《Django 5 By Example》阅读笔记:p645-p650

《Django 5 By Example》学习第8天&#xff0c;p645-p650总结&#xff0c;总计6页。 一、技术总结 1.django-rest-framework (1)serializer p648, Serializer: Provides serialization for normal Python class instances。Serializer又细分为Serializer, ModelSerializer,…

设计模式-Adapter(适配器模式)GO语言版本

前言 个人感觉Adapter模式核心就在于接口之间的转换。将已有的一些接口转换成其他接口形式。并且一般用于对象上&#xff0c;而不是系统上 问题 就用一个简单的问题&#xff0c;懂数据结构的同学可能知道双端队列。那么就用双端队列实现一个栈&#xff08;stack&#xff09;或…

【Pythonr入门第二讲】你好,世界

"Hello, World!" 是一种传统的编程入门示例&#xff0c;通常是程序员学习一门新编程语言时编写的第一个程序。这个程序的目标非常简单&#xff1a;在屏幕上输出 "Hello, World!" 这个字符串。尽管它非常简单&#xff0c;但具有重要的象征意义和实际价值。 …

「OpenCV交叉编译」ubuntu to arm64

Ubuntu x86_64 交叉编译OpenCV 为 arm64OpenCV4.5.5、cmake version 3.16.3交叉编译器 gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu 可在arm或linaro官网下载所需版本&#xff0c;本文的交叉编译器可点击链接跳转下载 Downloads | GNU-A Downloads – Arm Developer L…

PointNet++项目分析

好的&#xff0c;下面是每个文件和目录的详细说明&#xff1a; - **E:\Pointnet_Pointnet2_pytorch\-p**&#xff1a;这看起来像是命令行中的一个参数&#xff0c;而不是实际的文件&#xff0c;可能是误列。 - **E:\Pointnet_Pointnet2_pytorch\.gitattributes**&#xff1a;定…

聚焦 AUTO TECH 2025华南展:探索新能源汽车发展新趋势

随着“新四化”浪潮的推进&#xff0c;汽车行业正经历前所未有的变革。中国新能源汽车正逐渐走向世界。国内汽车制造巨头如比亚迪、吉利、奇瑞、长安等&#xff0c;已经将出口提升至核心战略地位。中国新能源汽车的发展&#xff0c;不仅推动了全球汽车产业的电动化转型&#xf…

JavaEE-网络编程(2)

目录 1. TCP的socket api 1.1 ServerSocket 1.2 Socket 1.3 关于连接 2. 写一个TCP回显服务器 代码的基本结构 2.1.建立连接 2.2 使用 try catch 语法 2.3 对操作流进行封装 2.4 使用 flush() 冲刷缓冲区 2.5 用 close() 关闭对客户端的连接 2.6 println 和 hasnex…

2.5D视觉——Aruco码定位检测

目录 1.什么是Aruco标记2.Aruco码解码说明2.1 Original ArUco2.2 预设的二维码字典2.3 大小Aruco二维码叠加 3.函数说明3.1 cv::aruco::detectMarkers3.2 cv::solvePnP 4.代码注解4.1 Landmark图说明4.2 算法源码注解 1.什么是Aruco标记 ArUco标记最初由S.Garrido-Jurado等人在…

云厂商双十一,无新可拉

失去意义的促销秀。 作者|文昌龙 编辑|杨舟 与电商平台双十一的“低价诱惑”和套路满满不同&#xff0c;云市场的双十一更像是一个买方市场&#xff0c;客户牢牢掌握主导权&#xff0c;厂商不得不低头争抢每一位潜在客户。 电商平台「双11」的本质&#xff0c;初始来看&…

Spring Boot出现java: 错误: 无效的源发行版:16的解决方式

第一步&#xff1a; 修改为SDK的目标字节码版本 第二步&#xff1a;CtrlShiftAltS进入项目结构 第三步&#xff1a;pom.xml文件中 在网上搜索和自己SDK适配的Springboot版本&#xff0c;1.8对应的是2.7.1&#xff08;可以用&#xff09; 修改Java版本为1.8 最后的最后&a…

删除k8s 或者docker运行失败的脚本

vi delete_exited_containers.sh#!/bin/bash# 列出所有停止的容器并存储到数组 list_exited_containers() {echo -e "\nStopped containers:"containers()# 获取停止的容器信息并存入数组while IFS read -r line; docontainers("$line")done < <(do…

Java之Spring MVC篇三

​​​​​​​ 目录 响应 返回静态页面 RestController 和 Controller的区别和联系 返回数据ResponseBody 关于ResponseBody 返回HTML代码片段 返回JSON 设置状态码 设置Header 设置Content-Type 没设置Content-Type之前 设置Content-Type之后 响应 返回静态页面…

Revisiting Prompt Engineering via Declarative Crowdsourcing

文章目录 题目摘要简介LLMS 和众包声明式提示工程讨论结论 题目 通过声明式众包重新审视快速工程 论文地址&#xff1a;https://arxiv.org/abs/2308.03854 摘要 大型语言模型 (LLM) 在理解和生成文本形式的数据方面非常强大&#xff0c;但很脆弱且容易出错。出现了以所谓的提…

数据库概述

1.为什么要使用数据库 使用数据库有以下几个重要原因&#xff1a; 数据的集中管理&#xff1a;数据库可以集中管理和存储大量的数据&#xff0c;而不需要将数据分散保存在不同的文件中。这样可以方便地对数据进行访问、修改和更新。 数据的持久化存储&#xff1a;数据库通过将…

嵌入式驱动开发详解1(系统调用)

文章目录 符设备驱动架构read函数详解用户层read函数内核层read函数 具体实现用户层代码 内核层代码细节分析 符设备驱动架构 如上图所示&#xff0c;应用层程序直接用系统提供的API函数即可调用驱动层相应的函数&#xff0c;中间的具体过程都是由linux内核实现的&#xff0c;…

开源 - Ideal库 - 枚举扩展设计思路及实现难点(三)

今天想和大家分享关于枚举扩展设计思路和在实现过程中遇到的难点。 01、设计思路 设计思路说起来其实也很简单&#xff0c;就是通过枚举相关信息&#xff1a;枚举值、枚举名、枚举描述、枚举项、枚举类型&#xff0c;进行各种转换&#xff0c;通过一个信息获取其他信息。比如通…

学习笔记021——Ubuntu 安装 MySQL 5.7版本

本文通过是Ubuntu自带的apt安装的。 目录 1、查看可安装 MySQL 版本 2、安装 3、设置密码、开启远程访问 4、修改 sql_mode 和 设置 不区分大小写。&#xff08;根据自己需求来定&#xff09; 5、改端口等设置&#xff1a; 6、启动命令 7、验证 1、查看可安装 MySQL 版…

IDE配置tomcat

1.导航到 Tomcat 安装目录 E:\apache-tomcat-9.0.95-windows-x64\apache-tomcat-9.0.95 2.启动 Tomcat 服务&#xff1a;bin\startup.bat