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

news2024/9/21 12:29:11

迭代器模式

    • 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()
    {
        //工厂模式,注意实参传递进去的是该容器的指针this
        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];
};
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)虽然不是传统意义上的迭代器,但它们提供了对动态分配内存的管理和访问,类似于迭代器的功能。

总结

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

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

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

相关文章

【kubernetes】相关pod的创建和命令

【书写方法】&#xff1a; 管理使用k8s集群时&#xff0c;创建资源的Yaml文件非常重要&#xff0c;如何快速手写呢&#xff1f; 根据命令提示书写&#xff1a; kubectl explain [资源名称]例如打算写pod资源文件时&#xff0c;可查看如下&#xff1a; # 查看pod下所有字段 …

20. elasticsearch进阶_数据可视化与日志管理

20. 数据可视化 本章概述一. `elasticsearch`实现数据统计1.1 创建用户信息索引1.1.1 控制台创建`aggs_user`索引1.1.2 `aggs_user`索引结构初始化1.1.3 `aggs_user`索引的`EO`对象1.1.4 用户类型枚举1.1.5 数据初始化1.2 内置统计聚合1.2.1 `terms`与`date_histogram``terms``…

RocketMQ指南(二)高级篇

高级篇 1. 高级功能 1.1 消息存储 分布式队列因为有高可靠性的要求&#xff0c;所以数据要进行持久化存储。 消息生成者发送消息MQ收到消息&#xff0c;将消息进行持久化&#xff0c;在存储中新增一条记录返回ACK给生产者MQ push 消息给对应的消费者&#xff0c;然后等待消…

一文学会Shell中case语句和函数

大家好呀&#xff01;今天简单聊一聊Shell中的case语句与函数。在多选择情况下使用case语句将非常方便&#xff0c;同时&#xff0c;函数的学习和使用对于学好一门编程语言也是非常重要的。 一、case语句 case语句为多选择语句。可以用case语句匹配一个值与一个模式&#xff0c…

g++,gcc

由一个错误引发对这个问题的关注 上面我对于cpp文件利用gcc进行编译时产生的错误&#xff0c;起初我以为时三方库安装版本问题&#xff0c;反复卸载重装&#xff0c;发现仍然没有解决。然后我把目光聚焦到gcc编译这&#xff0c;发现把gcc改成g&#xff0c;编译就通过了。 g和 …

回归分析系列14.2— 正则化回归

16 正则化回归 16.1 简介 正则化回归是一种在回归模型中引入约束的技术,目的是防止模型过拟合并提高其泛化能力。最常见的正则化方法有岭回归(L2正则化)和套索回归(L1正则化)。这些方法通过添加惩罚项来限制模型参数的大小,从而降低模型的复杂度。 16.2 岭回归(L2正则…

OpenStack命令行发放云主机

source keystonerc_admin 查看环境变量 创建租户&#xff08;项目&#xff09; openstack project create hds 创建用户 openstack user create hds --password 1 --project hds 追加角色 openstack role add_member --user hds --project hds 创建规格 openstack flavor cr…

警惕.mkp勒索病毒:如何有效预防.mkp勒索病毒攻击

导言&#xff1a; 在数字化时代&#xff0c;网络安全问题日益严峻&#xff0c;勒索病毒作为一种极具破坏性的恶意病毒&#xff0c;严重威胁着个人用户和企业机构的数据安全。其中&#xff0c;.mkp勒索病毒以其强大的加密能力和广泛的传播方式&#xff0c;成为近期备受关注的网…

Linux 命令重定向介绍

今天给伙伴们分享一下Linux 命令重定向&#xff0c;希望看了有所收获。 我是公众号「想吃西红柿」「云原生运维实战派」作者&#xff0c;对云原生运维感兴趣&#xff0c;也保持时刻学习&#xff0c;后续会分享工作中用到的运维技术&#xff0c;在运维的路上得到支持和共同进步&…

Linux磁盘实用指令

目录 磁盘实用指令 磁盘实用指令 显示opt目录下的文件和目录 。 筛选出第一个符号为-的。 wc指令统计数目。 将符号-改为d就可以统计目录数目。 添加一个大写的r就可以递归的显示子目录了。 再与之前同理筛选出文件即可。 包括子文件夹的话加个大写的r即可 。 没有是因为默认情…

第2章-07-客户端IP与UserAgent

🏆作者简介,黑夜开发者,CSDN领军人物,全栈领域优质创作者✌,CSDN博客专家,阿里云社区专家博主,2023年CSDN全站百大博主。 🏆数年电商行业从业经验,历任核心研发工程师,项目技术负责人。 🏆本文已收录于专栏:Web爬虫入门与实战精讲,后续完整更新内容如下。 文章…

WLAN基础概念与实验

目录 1.WLAN 1.1 WLAN 基本概念和用途 1.2 WLAN 的用途 2.实验基本信息 2.1 实验top 2.2 实验要求 3.实验配置 3.1 基础配置 3.1.1 Router 3.1.2 SW1 3.1.3 SW2 3.1.4 AC6605 3.2 上线配置&#xff08;AC6605&#xff09; 3.3无线的下发 3.3.1 配置用户认证方式…

论文翻译:Multi-step Jailbreaking Privacy Attacks on ChatGPT

Multi-step Jailbreaking Privacy Attacks on ChatGPT https://arxiv.org/pdf/2304.05197 多步骤越狱隐私攻击对ChatGPT的影响 文章目录 多步骤越狱隐私攻击对ChatGPT的影响摘要1 引言2 相关工作3 对ChatGPT的数据提取攻击3.1 数据收集3.2 攻击制定3.3 从ChatGPT中提取私人数据…

Day47 | 110.字符串接龙 105.有向图的完全可达性 106.岛屿的周长

110.字符串接龙 110. 字符串接龙 题目 题目描述 字典 strList 中从字符串 beginStr 和 endStr 的转换序列是一个按下述规格形成的序列&#xff1a; 1. 序列中第一个字符串是 beginStr。 2. 序列中最后一个字符串是 endStr。 3. 每次转换只能改变一个字符。 4. 转换过…

数据结构-时间、空间复杂度-详解

数据结构-时间复杂度-详解 1.前言1.1数据结构与算法1.2如何衡量一个算法的好坏1.3复杂度 2.时间复杂度2.1是什么2.2大O符号只保留最高阶项不带系数常数次为O(1) 2.3示例示例2.1示例2.2示例2.3示例2.4 2.4题目 3.空间复杂度3.1是什么3.2大O符号3.3示例示例1示例2示例3示例4 4.题…

用4种不同视角理解矩阵乘法

目录 1. 背景 2. 线性方程组视角&#xff08;向量点积视角&#xff09; 3. 列向量观点视角 4. 向量变换视角&#xff08;矩阵函数&#xff09; 5. 坐标变换视角 1. 背景 矩阵诞生于线性方程组的求解&#xff0c;最基本的运算方法来自于高斯消元法&#xff0c;所以矩阵整个…

一些问题的解决方案【持续更新ing】

一些问题的解决方案【持续更新ing】 WindowsCUDA 安装失败解决方案VS 添加现有项无反应无法定位程序输入点 于动态链接库 xxx.exe 上不同工具集生成的库无法通用更改只读属性 UbuntuVTK cmake 过程中找不到QT5目录Ubuntu添加环境变量&#xff08;永久最简单&#xff09;Wandb强…

书橱系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;图书信息管理&#xff0c;图书类型管理&#xff0c;电子书论坛&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;图书信息&#xff0c;电子书论坛&#xff0c;我的 开发系统…

SSRF实验

SSRF实验 SSRF概述实验测试结果 SSRF概述 SSRF服务端请求伪造&#xff0c;是因为网页提供的参数可以获取其他资源&#xff0c;接受网址在本地解析&#xff0c;来获取服务器本身的资源&#xff0c;但解析没过滤导致出现的问题 主要有几个方面的方法 dict 协议是一个在线网络字…

旅游社交小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;每日签到管理&#xff0c;景点推荐管理&#xff0c;景点分类管理&#xff0c;防疫查询管理&#xff0c;美食推荐管理&#xff0c;酒店推荐管理&#xff0c;周边推荐管理 微信端账…