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

devtools/2024/9/19 4:25:10/ 标签: c++, 设计模式, 迭代器模式

迭代器模式

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

迭代器模式是一种行为设计模式,旨在提供一种方法来顺序访问集合对象中的元素,而不暴露集合的内部结构。

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

1. 主要组成成分

  1. 迭代器接口 (Iterator):定义访问和遍历元素的基本方法,如 next(), hasNext(), currentItem() 等。
  2. 具体迭代器 (Concrete Iterator):实现迭代器接口,维护对集合的引用,并跟踪当前遍历的位置。
  3. 聚合接口 (Aggregate):定义创建迭代器的接口,通常包含一个方法如 createIterator()
  4. 具体聚合 (Concrete Aggregate):实现聚合接口,包含集合的具体数据结构(如数组、链表等),并实现创建迭代器的方法。

2. 迭代器模式范例

以下是一个简单的迭代器模式实现范例,使用一个固定大小的数组作为容器。

2.1 抽象迭代器

在抽象迭代器模板中实现了四个基本方法,这些方法通常被视为迭代器接口的最小要求。

//抽象迭代器类模板
template <typename T>
class myIter
{
public:virtual void First() = 0;     //指向容器中第一个元素virtual void Next() = 0;      //指向下一个元素virtual bool IsDone() = 0;    //是否遍历完virtual T& CurrentItem() = 0; //获取当前的元素virtual ~myIter() {}          //做父类时析构函数应该为虚函数
};
2.2 抽象容器

在抽象容器类模板中定义了一个 CreateIterator 接口,后续在具体的容器子类中,会运用工厂模式创建相应的迭代器。

//抽象容器类模板
template <typename T>
class myCotainer
{
public:virtual myIter<T>* CreateIterator() = 0; //创建迭代器virtual T& getItem(int index) = 0; //获取当前元素virtual int getSize() = 0;  //容器中元素数量virtual ~myCotainer() {}  //做父类时析构函数应该为虚函数
};
2.3 具体的迭代器

具体迭代器(myVectorIter)实现了抽象迭代器接口,并提供对具体容器(myVector)的访问和遍历功能。

//具体迭代器类模板,为简单起见,本迭代器针对的是大小为10个元素的数组
template <typename T>
class myVectorIter :public myIter<T>
{
public:myVectorIter(myCotainer<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:myCotainer<T>* myvector;int m_current;  //记录数组的当前下标(迭代器在当前容器中的位置)
};
2.4 具体的容器

具体容器(myVector)实现了抽象容器接口,负责存储数据、管理元素,并提供创建迭代器的功能。

//具体容器类模板
template <typename T>
class myVector :public myCotainer<T>
{
public:myVector(){//将数组中元素进行初始化for (int i = 0; i < 10; ++i){m_elem[i] = i;}}virtual myIter<T>* CreateIterator(){//工厂模式,注意实参传递进去的是该容器的指针thisreturn new myVectorIter<T>(this); //要考虑在哪里释放的问题}virtual T& getItem(int index){return m_elem[index];}virtual int getSize(){return 10; //为简化代码,返回固定数字}
private://为了简化代码,将容器实现为固定装入10个元素的数组T m_elem[10];
};
2.5 主函数示例

以下是两个不同实现的 main 函数,展示了如何使用迭代器。

使用具体迭代器(非多态机制):直接使用具体迭代器,性能更优,适合简单的遍历场景,因为它避免了多态引入的额外开销。

int main() 
{myCotainer<int>* pcontainer = new myVector<int>();myVectorIter<int> iter(pcontainer);//遍历容器中的元素for (iter.First(); !iter.IsDone(); iter.Next()) //非多态机制,可以明显改善程序性能{cout << iter.CurrentItem() << endl;}//释放资源delete pcontainer;return 0;
}

使用抽象迭代器(多态机制):使用抽象迭代器,提供了更大的灵活性和扩展性,但性能较低,适合需要不同迭代策略的复杂场景。下面代码中的for循环所调用的迭代器接口 FirstIsDoneNextCurrentItem 都是多态机制。显然,如果容器中的元素数量非常庞大,则会非常影响程序的运行效率。因此,如果不是必须使用迭代器的多态机制,可以将迭代器的内存在栈中分配,这对改善程序运行性能将起到很好的作用。

int main() 
{myCotainer<int>* pcontainer = new myVector<int>();myIter<int>* iter = pcontainer->CreateIterator();//遍历容器中的元素for (iter->First(); !iter->IsDone(); iter->Next()) //多态机制的遍历,效率上不好,尽量考虑栈机制{cout << iter->CurrentItem() << endl;}//释放资源delete iter;delete pcontainer;
}

无论使用哪种方式,输出结果都是:

0
1
2
3
4
5
6
7
8
9

3. 迭代器 UML 图

<a class=迭代器模式 UML 图" />

3.1 迭代器 UML 图解析
  • Iterator (抽象迭代器):用于定义访问和遍历容器中元素的接口。这部分对应 myIter 类模板。
  • ConcreteIterator (具体迭代器):实现了抽象迭代器的接口,完成对聚合对象(容器)中元素的遍历,记录当前元素的位置。这部分对应 myVectorIter 类模板。
  • Aggregate (抽象聚合):将聚合理解成容器,声明一个 CreateIterator 方法用于创建一个迭代器对象,充当创建迭代器的工厂角色。这部分对应 myContainer 类模板。
  • ConcreteAggregate (具体聚合):实现了抽象聚合的 CreateIterator 方法以创建相应的迭代器,该方法返回具体迭代器的一个适当实例。这部分对应 myVector 类模板。

4. 迭代器模式的优点

  • 单一职责原则迭代器模式将集合对象的遍历行为从集合对象本身分离出来,由迭代器负责,这样使得集合对象和迭代器各自承担单一的职责,降低它们之间的耦合。
  • 开闭原则迭代器模式支持以不同的方式遍历一个聚合对象,在不改变聚合对象结构的前提下,可以定义新的迭代器类来支持新的遍历方式。
  • 可扩展性:可以根据需要,增加新的迭代器类来扩展系统的功能,如实现反向迭代器或过滤迭代器等。
  • 封装性迭代器模式封装了遍历算法的细节,用户不需要知道集合对象的内部结构即可进行遍历。

5. 迭代器模式的缺点

  • 类爆炸:为了支持多种遍历方式,可能需要定义很多具体的迭代器类,增加了系统的复杂性。
  • 性能开销:使用迭代器模式可能比直接遍历集合对象要慢,因为需要通过接口进行函数调用,而不是直接访问数据。

6. 迭代器模式的适用场景

  • 访问聚合对象的内容而不暴露其内部表示迭代器模式允许客户端通过迭代器对象访问聚合对象的元素,而不需要了解聚合对象的具体实现。这种封装提高了代码的灵活性和可维护性。
  • 支持多种不同的遍历方式:在某些情况下,可能需要以不同的顺序或策略遍历同一个集合(例如前序遍历、后序遍历等)。迭代器模式可以轻松实现这些不同的遍历方式,而不需要修改聚合对象的内部结构。
  • 提供统一的接口来遍历不同的聚合结构迭代器模式为不同类型的聚合对象提供了一个共同的接口,使得客户端可以使用相同的方式遍历不同的集合。这种一致性简化了代码的使用,增强了可扩展性。
  • 需要支持并发遍历:在复杂系统中,可能需要多个线程同时遍历同一个集合。迭代器模式可以设计为支持并发访问,确保线程安全。
  • 需要在不暴露集合实现的情况下实现复杂的遍历逻辑:当遍历逻辑变得复杂时(例如,过滤、映射等),可以使用迭代器将这些逻辑与集合的实现分离,使代码更清晰。
  • 需要延迟加载或惰性求值迭代器模式可以实现惰性求值,只有在需要时才加载元素,从而节省内存和计算资源。

7. 现代C++中的迭代器

在C++标准库中,迭代器模式被广泛应用。C++标准库中的容器(如 std::vector, std::list, std::map 等)都提供了迭代器来访问容器中的元素。以下是C++中迭代器的一些特点:

  • 标准迭代器:C++标准库定义了五种迭代器类别,包括输入迭代器、输出迭代器、前向迭代器、双向迭代器和随机访问迭代器。
  • 迭代器适配器:C++还提供了迭代器适配器,如 std::reverse_iterator 用于反向遍历容器,std::istream_iteratorstd::ostream_iterator 用于流操作。
  • 泛型编程:迭代器与模板结合使用,可以实现泛型算法,如 std::sortstd::find 等算法可以用于任何提供相应迭代器接口的容器。
  • 智能指针:C++中的智能指针(如 std::unique_ptr, std::shared_ptr)虽然不是传统意义上的迭代器,但它们提供了对动态分配内存的管理和访问,类似于迭代器的功能。

总结

迭代器模式通过提供一种统一的接口来访问不同类型的集合,增强了代码的可读性和可维护性。尽管存在一些缺点,如类的增加和性能开销,但其优点使得在需要灵活访问集合的场景中非常有效。理解和应用迭代器模式对于提高编程能力和设计模式的掌握至关重要。


http://www.ppmy.cn/devtools/103241.html

相关文章

华为AR路由使用PPPoE获取IPv6地址上网

公司搬家&#xff0c;从原有的思科设备换成华为AR路由器&#xff0c;有空研究了下华为AR路由器通过PPPoE拨号获取v6地址&#xff0c;且通过DHCPv6-PD给内网客户端分配地址。 全局开启IPv6 ipv6基本PPPoE配置 interface Dialer1link-protocol pppppp chap user 011111063930p…

亚马逊aws的弹性与可扩展性解析

欢迎来到雲闪世界。可以使用各种服务和工具在 AWS 上实现可扩展性和弹性。例如&#xff0c;AWS Application Auto Scaling 是一种可以自动调整容量以低成本实现出色应用程序性能的服务。这允许轻松设置跨多个服务的多个资源的应用程序扩展。让我们来谈谈弹性和可扩展性之间的区…

Golang 教程2

Golang 教程2 注意&#xff0c;该文档只适合有编程基础的同学&#xff0c;这里的go教程只给出有区别的知识点 函数的基本形式 //形式 /* func 函数&#xff08;形参列表&#xff09;&#xff08;返回值类型列表&#xff09;{执行语句return 返回值列表 } */1、 一个返回值…

【hot100篇-python刷题记录】【最小路径和】

R6-多维动态规划篇 好经典的dp题&#xff0c;纯粹的题。 多维动态规划无论是二维还是三维&#xff0c;无非是创建dp表&#xff0c;dp[][][][][][]即可 动态规划式子 dp[i][j]当前值min(dp[i][j-1],dp[i-1][j]) 边界问题处理&#xff1a;是否存在即可。哦对了好像不用这样&a…

深入理解Seaborn库的高级功能(二)

Seaborn作为Python中一个功能强大的可视化库,建立在matplotlib的基础之上,提供了更高级的API,使得数据可视化的创建过程更为简便和直观。在实际的数据分析工作中,Seaborn不仅可以帮助我们快速绘制高质量的图表,还能通过丰富的图形种类和调色板选项,让数据展示更加生动、清…

智能优化特征选择|基于鲸鱼WOA优化算法实现的特征选择研究Matlab程序(KNN分类器)

智能优化特征选择|基于鲸鱼WOA优化算法实现的特征选择研究Matlab程序&#xff08;KNN分类器&#xff09; 文章目录 一、基本原理原理流程举个例子总结 二、实验结果三、核心代码四、代码获取五、总结 智能优化特征选择|基于鲸鱼WOA优化算法实现的特征选择研究Matlab程序&#x…

mysql8.0查询等级排名可使用窗口函数,那5.7的版本呢?

1、需求&#xff1a;查询用户详情的同时查询用户的排名 2、首先看下数据库表设计 分为会员用户表member_user和会员等级表member_level&#xff0c;升级的条件是根据经验值升级&#xff0c;表结构如下&#xff1a; 用户表 member_user CREATE TABLE member_user (id bigint(…

Dll中的回调函数

在C中&#xff0c;回调函数是一种常用的编程技术&#xff0c;用于在某个事件发生时通知主程序。在您描述的场景中&#xff0c;DLL会从某个来源接收数据&#xff0c;并在处理完毕后通过回调函数通知主程序。以下是实现这一机制的基本步骤&#xff1a; 1. **定义回调函数原型**&…

炫光HUD杂散光测试方法及设备

HUD杂散光测试概述 HUD&#xff08;Heads-Up Display&#xff09;抬头显示器是现代汽车中的一项先进技术&#xff0c;它可以将重要信息如速度、导航等投射在驾驶员的视线前方&#xff0c;从而减少低头查看仪表盘的次数&#xff0c;提高行车安全。然而&#xff0c;HUD在实际使用…

用户ISP

用户ISP&#xff08;Internet Service Provider&#xff0c;互联网服务提供商&#xff09;是指向用户提供接入互联网服务的公司或组织。ISP通过各种技术手段&#xff08;如拨号、DSL、光纤、无线等&#xff09;为个人、企业和其他组织提供互联网连接服务。用户通过ISP连接到互联…

信息学奥赛初赛天天练-75-NOIP2016普及组-完善程序-二分答案、二分查找、贪心算法、贪心策略

文章PDF链接: https://pan.baidu.com/s/1SVcGU_rApvoUWrUoviPCiA?pwdht2j 提取码: ht2j 复制这段内容后打开百度网盘手机App&#xff0c;操作更方便哦 1 完善程序 (单选题 &#xff0c;每小题3分&#xff0c;共30分) 郊游活动 有 n名同学参加学校组织的郊游活动&#xff0c…

erlang学习:用OTP构建系统2,警报管理

今日学习用OTP构建系统的警报管理&#xff0c; 首先进行配置错误记录器 [{sasl,[{sasl_error_logger, false},{error_logger_mf_dir, "/code/erlang/erlangstudy"},{error_logger_mf_maxbytes, 10485760},{error_logger_mf_maxfiles, 10}]} ].警报处理器gen_event的…

苹果手机系统修复如何操作,几种iOS系统修复办法分享

苹果手机作为市场上的热门产品&#xff0c;其系统稳定性和用户体验一直备受赞誉。然而&#xff0c;即使是如此优秀的系统&#xff0c;也难免会遇到一些问题&#xff0c;如系统崩溃、应用闪退、无限重启等。当这些问题出现时&#xff0c;如何进行系统修复成为了许多用户关心的问…

常见的服务器容器和漏洞类型汇总

常见的服务器容器和漏洞有哪些&#xff1f;常见的服务器容器包括KubeSphere、Tomcat、Nginx、Apache等&#xff0c;它们在提供便捷的服务部署和灵活的网络功能的同时&#xff0c;也可能存在着一定的安全风险。这些容器的漏洞可能导致数据泄露、权限被非授权访问甚至系统被完全控…

GMS——利用 ChatGPT 和扩散模型进行制造业革命

概述 论文地址&#xff1a;https://arxiv.org/abs/2405.00958 研究介绍了生成式制造系统&#xff08;GMS&#xff09;&#xff0c;并表明这些系统能有效管理和协调自主制造资产&#xff0c;提高它们对不同生产目标和人类偏好的响应能力和灵活性。 与传统的显式建模不同&#…

深度全面讲解fs.readFileSync:Node.js中的同步文件读取

在Node.js中&#xff0c;fs模块是用于与文件系统交互的核心模块之一。它提供了一系列的方法用于文件的读取、写入、删除等操作。其中&#xff0c;fs.readFileSync是一个常用的同步方法&#xff0c;用于读取文件的内容。本文将深度全面讲解fs.readFileSync的使用&#xff0c;包括…

您应该让 ChatGPT 控制您的浏览器吗?

本文: 介绍授予大型语言模型 (LLM) 对 Web 浏览器的控制权的安全风险,重点关注提示注入漏洞。 通过两种场景演示了使用 Taxy AI(一种代表性概念验证浏览器代理)的利用,攻击者设法劫持代理并 (1) 从用户邮箱中窃取机密信息,(2) 强制合并 GitHub 存储库上的恶意拉取请求。 …

HTTPS

对称加密&#xff1a; 发送方和接受方用同样的规则来为数据进行加密&#xff0c;也可以说用同样的密钥来解开密文。 问题是&#xff1a;如何有第三方知道加密和解密规则后就很容易破解。 非对称加密&#xff1a; 用两个密钥来进行加密和解密&#xff0c;公开密钥是所有人都知道…

【Yarn】Yarn的基本执行流程(二)AM Container的启动

Yarn的基本执行流程之AM Container的启动 文章目录 Yarn的基本执行流程之AM Container的启动AM Container&#xff08;第一个Container&#xff09;的启动NM RM心跳交互触发调度Container的启动流程RM中调度启动AM流程AMLauncher启动流程NM上容器的启动流程下载资源AM Containe…

【React】Redux-toolkit 处理异步操作

安装 npm install reduxjs/toolkit react-redux创建 store src\store\index.js import { configureStore } from reduxjs/toolkit; import homeReducer from ./modules/home;const store configureStore({reducer: {home: homeReducer,}, });export default store;创建 Red…