当前位置: 首页 > news >正文

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

迭代器模式

    • C++ 设计模式——迭代器模式
      • 1. 主要组成成分
      • 2. 迭代器模式范例
        • 2.1 抽象迭代器
        • 2.2 抽象容器
        • 2.3 具体的迭代器
        • 2.4 具体的容器
        • 2.5 主函数示例
      • 3. 迭代器 UML 图
          • 3.1 迭代器 UML 图解析
      • 4. 迭代器模式的优点
      • 5. 迭代器模式的缺点
      • 6. 迭代器模式的适用场景
      • 7. 现代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 图

迭代器模式 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)虽然不是传统意义上的迭代器,但它们提供了对动态分配内存的管理和访问,类似于迭代器的功能。

总结

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

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 令牌和签名详细介绍+开发使用教程
  • 聚星文社下载地址
  • 光性能 -- OSNR,BER与Q值
  • Nginx 405 not allowed
  • WPS宏实现Sheet页合并功能
  • 区间预测|基于灰狼优化最小二乘支持向量机的多变量回归区间预测Matlab程序GWO-LSSVM-ABKDE
  • 做项目过程中问题小汇总 | vue3 elementplus js
  • DDoS攻击导致服务器宕机的技术解析
  • PXE-Kickstart高效批量装机
  • 32 - III. 从上到下打印二叉树 III
  • 回答评论:使用流遍历文件 list
  • EmguCV学习笔记 VB.Net 6.5 凸包和凸缺陷
  • laravel发送邮件的使用方法?有哪些技巧?
  • 计算机毕业设计选题推荐-游戏比赛网上售票系统-Java/Python项目实战
  • 【MySQL数据库管理问答题】第2章 安装和升级MySQL
  • 5分钟即可掌握的前端高效利器:JavaScript 策略模式
  • CentOS7简单部署NFS
  • Docker入门(二) - Dockerfile
  • Flannel解读
  • isset在php5.6-和php7.0+的一些差异
  • Java Agent 学习笔记
  • JavaScript DOM 10 - 滚动
  • Js基础——数据类型之Null和Undefined
  • VuePress 静态网站生成
  • WebSocket使用
  • 海量大数据大屏分析展示一步到位:DataWorks数据服务+MaxCompute Lightning对接DataV最佳实践...
  • 基于Android乐音识别(2)
  • 判断客户端类型,Android,iOS,PC
  • 进程与线程(三)——进程/线程间通信
  • ​ 全球云科技基础设施:亚马逊云科技的海外服务器网络如何演进
  • ​​​​​​​GitLab 之 GitLab-Runner 安装,配置与问题汇总
  • ​LeetCode解法汇总2182. 构造限制重复的字符串
  • # 详解 JS 中的事件循环、宏/微任务、Primise对象、定时器函数,以及其在工作中的应用和注意事项
  • (8)STL算法之替换
  • (LeetCode) T14. Longest Common Prefix
  • (Redis使用系列) Springboot 在redis中使用BloomFilter布隆过滤器机制 六
  • (附源码)springboot宠物医疗服务网站 毕业设计688413
  • (附源码)计算机毕业设计ssm基于B_S的汽车售后服务管理系统
  • (函数)颠倒字符串顺序(C语言)
  • (推荐)叮当——中文语音对话机器人
  • (一)kafka实战——kafka源码编译启动
  • (一)Linux+Windows下安装ffmpeg
  • (一)Thymeleaf用法——Thymeleaf简介
  • .bat批处理(八):各种形式的变量%0、%i、%%i、var、%var%、!var!的含义和区别
  • .bat批处理出现中文乱码的情况
  • .env.development、.env.production、.env.staging
  • .NET 发展历程
  • .Net中的集合
  • //解决validator验证插件多个name相同只验证第一的问题
  • @antv/x6 利用interacting方法来设置禁止结点移动的方法实现。
  • @select 怎么写存储过程_你知道select语句和update语句分别是怎么执行的吗?
  • @TableId注解详细介绍 mybaits 实体类主键注解
  • [000-002-01].数据库调优相关学习
  • [30期] 我的学习方法
  • [AIGC] Kong:一个强大的 API 网关和服务平台