C++设计模式——Iterator迭代器模式

news/2024/9/18 18:28:45/ 标签: c++, 设计模式, 迭代器模式, 开发语言, c语言, linux

一,迭代器模式的定义

迭代器模式是一种行为型设计模式,它使得遍历一个容器对象中的元素变得更加简单。

迭代器模式将遍历操作从容器对象(如集合、列表)中分离出来,它通过迭代器对象来遍历容器对象中的元素,使得遍历操作与容器对象解耦。

迭代器模式可以解决的需求场景是当容器对象内部的结构经常被改变时,需要对外部屏蔽其变化过程。

迭代器模式对外提供了一个统一的遍历接口,这个接口可以顺序访问容器对象中的每个元素。

迭代器模式提供了遍历容器对象的方法,同时也隐藏了容器对象的实现细节,对容器对象的修改不影响迭代操作的使用。

迭代器模式在现实生活中的抽象实例:

1.图书馆中的书籍:在一个图书馆中,书籍可以看作是一个集合,每本书可以使用迭代器来逐个遍历。

2.超市货架上的商品:在超市中,货架上的商品可以使用迭代器来逐个检查和选择。

3.音乐播放器中的歌曲列表:在音乐播放器中,歌曲列表可以使用迭代器来逐个播放歌曲。

4.咖啡馆中的菜单:在咖啡馆中,菜单可以使用迭代器来逐个展示每种饮品和食物的信息。

在编程开发场景,迭代器的设计与实现有两种方式:

1.内部迭代器:通常是容器本身,由迭代器自身控制遍历过程,自发进行容器对象的访问和遍历,例如std::vector<int>,std::map<char, int>等。

2.外部迭代器:通常是独立于容器的接口,由调用者控制遍历过程,需要显示地访问容器对象中的元素,例如std::forward_iterator_tag等。

代码样例:

Demo1:内部迭代器

#include <iostream>
#include <vector>int main() {std::vector<int> vec = { 1, 2, 3, 4, 5 };for (auto it = vec.begin(); it != vec.end(); ++it) {std::cout << *it << " ";}return 0;
}

运行结果:

1 2 3 4 5

Demo2:外部迭代器

#include <iostream>
#include <list>
#include <algorithm>
#include <string>class MyData {
public:MyData(int tmpValue) {value = tmpValue;}int value;
};template<typename T, typename OutIt>
OutIt print_data(const std::list<T>& container, OutIt out) {for (const auto& data : container) {*out++ = " [";*out++ = std::to_string(data.value);*out++ = "]";}return out;
}int main() {std::list<MyData> dataList = { 10, 20, 30, 40, 50 };std::ostream_iterator<std::string> outIter(std::cout, "");print_data(dataList, outIter);return 0;
}

运行结果:

[10] [20] [30] [40] [50]

二,迭代器模式的结构

迭代器模式主要包含以下组件:

1.迭代器(Iterator):

定义了迭代器的接口,包括获取下一个元素、判断是否还有下一个元素等方法。负责定义访问和遍历元素的接口。

2.具体迭代器(ConcreteIterator):

包含对迭代器接口的具体实现。

3.容器(Aggregate):

定义了容器对象的接口,包括获取迭代器、添加元素等方法。还提供了创建迭代器对象的接口。

4.具体容器(ConcreteAggregate):

包含对容器的具体实现。通常会在具体容器中返回一个具体迭代器对象。

组件之间的工作步骤如下:

1.客户端通过容器对象获取迭代器对象。

2.客户端使用迭代器对象进行遍历操作,获取容器中的元素。

3.迭代器对象根据容器的具体实现,在每次调用获取下一个元素的方法时返回容器中的下一个元素。

4.客户端使用迭代器对象的判断是否有下一个元素的方法,来判断是否继续遍历容器中的元素。

5.客户端根据具体的业务逻辑来处理遍历到的每个元素。

对应UML类图:

三,迭代器模式代码样例

#include <iostream>
#include <vector>class Iterator {
public:virtual bool hasNext() const = 0;virtual int next() = 0;
};class ConcreteIterator: public Iterator {
private:std::vector<int> Aggregate;int index = 0;
public:ConcreteIterator(const std::vector<int>& vec){Aggregate = vec;}bool hasNext() const override {return index < Aggregate.size();}int next() override {return Aggregate[index++];}
};class Aggregate {
public:virtual Iterator* createIterator() const = 0;
};class ConcreteAggregate : public Aggregate {
private:std::vector<int> elements;
public:ConcreteAggregate(const std::vector<int>& vec){elements = vec;}Iterator* createIterator() const override {return new ConcreteIterator(elements);}
};void traverseElements(ConcreteAggregate Aggregate) {Iterator* iterator = Aggregate.createIterator();while (iterator->hasNext()) {int element = iterator->next();std::cout << element << " ";}std::cout << std::endl;delete iterator;
}int main() {std::vector<int> elements = { 1, 2, 3, 4, 5 };ConcreteAggregate Aggregate(elements);traverseElements(Aggregate);return 0;
}

运行结果:

1 2 3 4 5

四,迭代器模式的应用场景

数据的分层访问:当数据源复杂且需要逐步解析时,迭代器使得上层代码可以按需获取数据,而不必关心底层实现的细节。

流式处理:在大数据处理场景,通常采用惰性加载或逐行读取的方式,只在需要时才请求下一个元素,类似于缓存机制。

算法封装:许多高级算法,如排序、搜索和图计算等,都可以用迭代器来驱动,这样既通用又灵活。

数据库查询:数据库API通常会提供游标,用户借助游标逐条获取查询结果,而无需了解具体的SQL执行细节。

文件系统开发:在读取大文件或目录树时,使用迭代器模式来依次访问每个文件或子目录,避免一次性加载所有内容导致内存溢出。

五,迭代器模式的优缺点

迭代器模式的优点:

简化了对容器对象的遍历操作,提供了一个统一的遍历接口。

将遍历操作与容器对象进行了解耦,使得容器对象可以独立变化。

处理大批量数据时,操作简单。

迭代器模式的缺点:

通常按顺序进行遍历,不支持直接索引访问,无法做到高效获取元素。

需要时刻维护自己的状态,如当前位置,不当使用可能导致错误。

每次遍历都需要创建一个新的迭代器对象,内存消耗大。

六,代码实战

基于迭代器模式封装的链表

#include <iostream>template <typename T>
struct Node {T data;Node* next;
};template <typename T>
class Iterator {
public:virtual T next() = 0;virtual bool hasNext() = 0;
};template <typename T>
class LinkedListIterator : public Iterator<T> {
public:LinkedListIterator(Node<T>* start){current_ = start;}T next() override {T data = current_->data;current_ = current_->next;return data;}bool hasNext() override {return current_ != nullptr;}
private:Node<T>* current_;
};int main() {Node<int>* head = nullptr;for (int i = 6; i >= 1; i--) {Node<int>* newNode = new Node<int>{ i, head };head = newNode;}Iterator<int>* iterator = new LinkedListIterator<int>(head);while (iterator->hasNext()) {std::cout << iterator->next() << " ";}while (head != nullptr) {Node<int>* temp = head;head = head->next;delete temp;}delete iterator;return 0;
}

运行结果:

1 2 3 4 5 6

七,参考阅读

https://softwarepatterns.com/cpp/iterator-software-pattern-cpp-example

https://www.geeksforgeeks.org/iterator-pattern/

http://qiusuoge.com/13723.html

https://www.geeksforgeeks.org/stdistream_iterator-stdostream_iterator-c-stl/

https://en.cppreference.com/w/cpp/iterator/next


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

相关文章

基于SpringBoot的求职招聘管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于JavaSpringBootVueMySQL的求职招聘管理系统…

Java 类和对象-小结(重要)

1&#xff0e;类和对象&#xff1a;类是一个模板&#xff0c;抽象的&#xff0c;对象是一个具体的实例。 2&#xff0e;方法&#xff1a;定义和调用 3&#xff0e;对象的引用&#xff1a; &#xff08;1&#xff09;除了八大基本类型之外&#xff0c;都是引用类型。 &#…

Ubuntu20-xrdp与Windows-mstsc远程桌面连接

ubuntu端 sudo adduser yu //输入密码和确认密码&#xff0c;后面一路回车&#xff0c;新建用户yu&#xff0c;确保用户没有被登录 sudo apt install xrdp //安装xrdp sudo systemctl status xrdp //查看xrdp服务状态 sudo adduser xrdp ssl-cert //将用户 xrdp 添加到 ss…

Hive和Hbase的区别

Hive 和 HBase 都是 Hadoop 生态系统中的重要组件&#xff0c;它们都能处理大规模数据&#xff0c;但各自有不同的适用场景和设计理念。以下是两者的主要区别&#xff1a; 1. 数据模型 Hive&#xff1a;Hive 类似于传统的关系型数据库 (RDBMS)&#xff0c;以表格形式存储数据…

动态ip切换过快,会引起我的账号下次登录异常吗

在网络世界中&#xff0c;动态IP地址的使用为用户提供了灵活性和隐私保护。然而&#xff0c;频繁且快速地切换IP地址可能会引起一些安全问题&#xff0c;尤其是在涉及到账号登录时。本文将探讨动态IP切换过快是否会导致账号登录异常&#xff0c;以及如何平衡IP切换的速度与账号…

k8s--pod控制器--1

Pod控制器介绍 Pod是kubernetes的最小管理单元&#xff0c;在kubernetes中&#xff0c;按照pod的创建方式可以将其分为两类&#xff1a; 自主式pod&#xff1a;kubernetes直接创建出来的Pod&#xff0c;这种pod删除后就没有了&#xff0c;也不会重建 控制器创建的pod&#xf…

前端工程化2:从0到1的eslint插件开发教程

从0-1的eslint插件开发教程 开发eslint插件目的&#xff1a;根据项目需要&#xff0c;自定义满足项目特殊需要的校验规则是 参考eslint官方文档展开阐述 插件开发 自定义规则 单元测试 下面开始通过一个示例demo来介绍插件整个开发流程 代码中出现的方法及变量的详细解释与…

NoSQL之Redis配置与优化(2)

一、Redis高可用 Redis 高可用性 1. 持久化 目的&#xff1a;避免数据因进程退出等原因而丢失&#xff0c;通过将数据从内存保存到硬盘&#xff0c;实现数据备份。主要方式&#xff1a; RDB 持久化&#xff1a;将内存中的数据生成快照保存到磁盘。适合定期备份数据&#xff…

深入理解 Vue 3 中的易混淆概念:全面解析及最佳实践20240909

深入理解 Vue 3 中的易混淆概念&#xff1a;全面解析及最佳实践 引言 Vue 3 的发布为前端开发带来了全新的组合式 API&#xff0c;这一革新使得代码的可维护性和复用性大大提升。然而&#xff0c;随着这些新特性的引入&#xff0c;也带来了一些容易混淆的概念。无论你是初学者…

微积分复习笔记 Calculus Volume 1 - 1.5 Exponential and Logarithmic Functions

1.5 Exponential and Logarithmic Functions - Calculus Volume 1 | OpenStax

package.json中~1.0.0和^1.0.0有什么区别

~会匹配最近的小版本依赖包&#xff0c;比如~1.2.3会匹配所有1.2.0 ~ 1.2.9 版本&#xff0c;但是不包括1.3.0&#xff0c;也就是1.2.x ^会匹配最新的大版本依赖包&#xff0c;比如^1.2.3会匹配所有1.x.x的包&#xff0c;包括1.3.0&#xff0c;但是不包括2.0.0 注意 如果前面…

数据库运维实操优质文章文档分享(含Oracle、MySQL等) | 2024年8月刊

本文为大家整理了墨天轮数据社区2024年8月发布的优质技术文章/文档&#xff0c;主题涵盖Oracle、MySQL、PostgreSQL等主流数据库系统以及国产数据库的技术实操&#xff0c;从基础的安装配置到复杂的故障排查&#xff0c;再到性能优化的实用技巧及常用脚本等&#xff0c;分享给大…

并行计算范式的时空辩证

来读一篇早年(September 27, 2017)的文章&#xff1a;The network era requires new models, with interactions instead of algorithms. 这篇文章迟到了很久&#xff0c;我在十多年前提到过一个相关的时空辩证&#xff1a; CPU 在时间序顺序执行指令流&#xff0c;基于图灵机…

职业技能大赛背景下的移动互联网应用软件开发(Android)实训室建设方案

一、建设背景 随着科技的持续进步&#xff0c;移动设备已成为人们日常生活中不可或缺的一部分。据相关数据&#xff0c;移动互联网的使用率在近年来显著上升。在这样的背景下&#xff0c;移动互联技术不仅推动了科技的发展&#xff0c;也渗透到了智能家居、车联网、工业自动化…

blender云渲染来了,blender云渲染教程!

朋友们&#xff0c;成都渲染101农场blender云渲染上线了&#xff0c;继3DMAX/C4D/maya/UE5云渲染上线后&#xff0c;又上线了blender云渲染&#xff0c;今天&#xff0c;成都渲染101渲染农场用四步教会您blender云渲染&#xff01; 第一步&#xff0c;云渲码6666注册个渲染101…

CSS Clip-Path:重塑元素边界的艺术

在Web设计中&#xff0c;创造独特而富有吸引力的视觉效果一直是设计师和开发者们追求的目标。CSS的clip-path属性为此提供了一个强大的工具&#xff0c;它允许我们定义元素的可见区域&#xff0c;从而以非矩形的方式裁剪图像或容器。这一特性不仅限于简单的形状裁剪&#xff0c…

深入理解Oracle数据库中的数据库链接

在Oracle数据库环境中&#xff0c;数据库链接&#xff08;Database Link&#xff09;是一种强大的特性&#xff0c;它允许用户从一个数据库&#xff08;本地数据库&#xff09;访问另一个数据库&#xff08;远程数据库&#xff09;中的数据。这种链接机制极大地增强了数据库的互…

一码空传临时网盘PHP源码,支持提取码功能

源码介绍 一码空传临时网盘源码V2.0免费授权&#xff0c;该源码提供了一个简单易用的无数据库版临时网盘解决方案。前端采用了layui开发框架&#xff0c;后端使用原生PHP编写&#xff0c;没有引入任何开发框架&#xff0c;保持了代码的简洁和高效。 这个程序使用了一个无数据…

对齐访问与非对齐访问

对齐访问与非对齐访问 一、对齐访问的定义对齐示例&#xff1a; 二、非对齐访问的定义非对齐示例&#xff1a; 三、对齐与非对齐访问的区别1. 性能&#xff1a;2. 处理器架构&#xff1a;3. 处理复杂度&#xff1a; 四、对齐与非对齐访问的实际应用1. 编译器优化&#xff1a;2.…

vscode 设置

code runner设置运行代码弹出运行窗口 要让VSCode在输cmd窗口&#xff0c;可以按照以下步骤进行设置&#xff1a; 1. 打开VSCode并进入”文件”->”首选项”->”设置”&#xff0c;或者使用快捷键Ctrl ,。 2. 在设置页面的搜索栏中输入”External Terminal”&#xf…