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

news/2024/9/20 3:56:06/ 标签: 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/news/1517536.html

相关文章

后端Web之登录校验(下篇)

目录 1.概述 ​2.过滤器Fliter 3.拦截器Interceptor 1.概述 Filter过滤器&#xff1a;在Web开发中&#xff0c;过滤器&#xff08;Filter&#xff09;是一种非常重要的组件&#xff0c;用于在请求到达目标资源&#xff08;如Servlet或静态资源&#xff09;之前或之后&#…

京东商品信息高效抓取:利用API实现数据获取的实战指南

在当今的电商时代&#xff0c;数据成为了企业决策和市场分析的重要基石。对于希望深入了解京东平台商品信息、优化供应链管理、或进行市场调研的商家和开发者而言&#xff0c;如何高效地获取京东商品信息成为了一项关键技能。本文将引导您通过API&#xff08;应用程序接口&…

零基础5分钟上手亚马逊云科技-云原生架构设计

简介&#xff1a; 欢迎来到小李哥全新亚马逊云科技AWS云计算知识学习系列&#xff0c;适用于任何无云计算或者亚马逊云科技技术背景的开发者&#xff0c;通过这篇文章大家零基础5分钟就能完全学会亚马逊云科技一个经典的服务开发架构方案。 我会每天介绍一个基于亚马逊云科技…

当代传输算法以及其效率和公平

我不再提拥塞控制算法&#xff0c;因为当代一个好的&#xff0c;正常的传输算法本应该天然主动避免拥塞&#xff0c;而不是拥塞了再控制&#xff0c;本着这个思路&#xff0c;我甚至觉得 bbr 的 probe 都是一种 capacity-seeking 行为&#xff0c;而 capacity-seeking 是一定会…

简单分享下Python文件压缩与解压

在日常开发和数据处理中&#xff0c;文件的压缩与解压是一项基础而实用的技能。Python通过zipfile和tarfile模块提供了强大的文件压缩和解压缩功能。下面&#xff0c;我们将通过10个实战技巧&#xff0c;一步步深入学习如何高效地操作文件压缩包。 技巧1: 创建ZIP压缩文件 目…

会议音频方案

会议音频方案往往会根据会议室的大小、形状和用途等因素进行定制。不同的会议环境需要不同的音频解决方案&#xff0c;以确保声音的清晰度、覆盖范围和回声控制。以下是根据会议室大小和用途定制音频方案的关键考虑因素&#xff1a; 1. 小型会议室通常容纳4-10人&#xff0c;房…

rockyliunx 救援模式下禁用docker

目录地址 /usr/lib/systemd/system/docker.service 进入系统界面&#xff1a; 选择系统 按E 按e出现 如下界面&#xff0c;找到 quite 后面添加 init/bin/bash 按 ctrl x 保存 后&#xff0c;到如下界面 加载文件系统为读写 输入命令 mount -o remount, rw / 修改docer.s…

etcd v2/v3 最全常用命令差异

etcd v2/v3 最全常用命令差异 在分布式系统中&#xff0c;ETCD作为一个高性能、可靠且安全的键值存储系统&#xff0c;广泛应用于配置共享、服务发现、分布式锁等多个领域。 下面整理了v2/v3版本中命令的使用差异。 1. 查看集群状态 使用etcdctl member list命令可以查看ETC…

HarmonyOS 鸿蒙获取微信授权和持续获取位置信息

获取授权 PermissionManager.ets import { BusinessError } from "kit.BasicServicesKit"; import { abilityAccessCtrl, bundleManager, PermissionRequestResult, Permissions, common ,Want} from "kit.AbilityKit";/*** 查询是否有单个权限* param pe…

前端环境配置

GIT 安装 官网下载进行安装 前往下载已有项目执行git&#xff08;电脑C盘格式化&#xff0c;但是项目盘保留&#xff09;&#xff0c;可执行 git config --global --add safe.directory 项目绝对路径连接公司git&#xff1a; 命令rsa得到ssh key&#xff0c;添加到git网站配置…

华为Cloud连接配置

Cloud(云)连接意思为本地电脑和eNSP中的虚拟的VRP系统连接的 配置Cloud 先添加UDP 再添加需要使用的网卡 网卡建议使用虚拟机的网卡&#xff0c;如果没有虚拟机也可以使用其他网卡&#xff0c;自己设定一下IP就行 端口映射设置 配置R1 [R1]int e0/0/0 [R1-Ethernet0/0/0]ip …

双系统ubuntu引导项丢失如何修复

本来是win11和ubunt22.04的双系统&#xff0c;但是现在工作需要做一个外接固态里安装ubunt22.04去安装autoware, 按照装双系统的方法也装上了&#xff0c;引导项不知怎么回事&#xff0c;被设置在外接固态硬盘中了&#xff0c;导致开机必须插上外接固态才能进入引导项&#xff…

解决npm下载依赖速度慢的问题

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

智能儿童对讲机语音交互,乐鑫ESP-RTC音视频通信,ESP32无线语音方案

儿童对讲机一种专为孩子们设计的通讯设备&#xff0c;可以让父母与孩子之间进行双向通讯&#xff0c;增强亲子关系&#xff0c;增强孩子的可玩性。 儿童对讲机近几年发展的比较快&#xff0c;通过无线WiFi及蓝牙通信技术&#xff0c;可以实现远程控制和语音交互功能&#xff0…

浅析车辆类型检测算法实际应用车辆类型检测算法源码

随着交通运输和物流需求的不断增长&#xff0c;车辆类型检测的准确性和效率成为了一个关键问题。传统的检测方法往往依赖人工和基础的识别技术&#xff0c;面对日益复杂的交通环境&#xff0c;这些方法显得力不从心。幸运的是&#xff0c;智能算法的应用为这一问题带来了突破性…

MySQL 延迟从库介绍

前言&#xff1a; 我们都知道&#xff0c;MySQL 主从延迟是一件很难避免的情况&#xff0c;从库难免会偶尔追不上主库&#xff0c;特别是主库有大事务或者执行 DDL 的时候。MySQL 除了这种正常从库外&#xff0c;还可以设置延迟从库&#xff0c;顾名思义就是故意让从库落后于主…

考研系列-数据结构第八章:排序(下)

一、归并排序 1.算法思想 基本思想是将一个数组分成两半,对这两半分别进行排序,然后将排序好的两半合并在一起。这个过程一直递归进行,直到划分的子数组只包含一个元素(此时认为该元素已经排序好),然后开始合并过程,直到合并为一个完整的、排序好的数组。 2.具体步骤 …

C++设计模式6:适配器模式

适配器模式的主要目的&#xff0c;是让不兼容的接口可以在一起工作&#xff0c;当我们自己的项目接口与一些第三方库的接口不兼容的时候&#xff0c;就需要用到适配器&#xff0c;或者我们自己重构自己的代码&#xff0c;显然后者的代价比较大。 假如&#xff0c;我们有一种电脑…

【设计模式之建造者模式——自行车加工】

背景&#xff1a; 软件开发过程中有的时候需要创建很复杂的对象&#xff0c; ⽽建造者模式的主要思想是将对象的构建过程分为多个步骤&#xff0c;并为每个步骤定义⼀个抽象的接⼝。 具体的构建过程&#xff1a;由实现了这些接⼝的具体建造者类来完成。同时有⼀个指导者类负责…

如何设置Winfrom中dataGridView中的内容换行并行高自适应

如何设置Winfrom中dataGridView行高 在 Windows Forms (WinForms) 应用程序中&#xff0c;DataGridView 控件用于显示和编辑数据的表格形式。如果你想要设置 DataGridView 控件中行的高度&#xff0c;可以通过以下几种方式来实现&#xff1a; 1. 通过属性设置行高 你可以直接…