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

一,迭代器模式的定义

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

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

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

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

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

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

RK3568平台开发系列讲解(PWM篇)使用 sysfs 接口操作 pwm

🚀返回专栏总目录 文章目录 一、查看 pwm 设备信息二、使用 sysfs 操作 PWM沉淀、分享、成长,让自己和他人都能有所收获!😄 PWM 子系统被划分为了三个层次, 分别为用户空间、 内核空间和硬件层, 内核空间包括 PWM 设备驱动层、 PWM 核心层和 PWM 适配器驱动层 一、查看…

JS面试真题 part3

JS面试真题 part3 11、bind、call、apply区别&#xff1f;如何实现一个bind12、JavaScript中执行上下文和执行栈是什么13、说说JavaScript中的事件模型14、解释下什么是事件代理&#xff1f;应用场景&#xff1f;15、说说你对闭包的理解&#xff1f;闭包使用场景 11、bind、cal…

分布式技术概览

文章目录 分布式技术1. 分布式数据库&#xff08;Distributed Databases&#xff09;2. 分布式文件系统&#xff08;Distributed File Systems&#xff09;3. 分布式哈希表&#xff08;Distributed Hash Tables, DHTs&#xff09;4. 分布式缓存&#xff08;Distributed Caching…

面向对象需求分析

1. 面向对象分析概述 1.1 面向对象基本概念 以对象为中心&#xff0c;以类为构造机制&#xff0c;来认识、理解、刻画客观世界和设计、构建相应的软件系统。 1.2 UML统一建模语言 为什么要使用UML UML基本概念 统一建模语言&#xff08;UML&#xff09;是一个支持模型化和软…

【电子通识】半导体工艺——刻蚀工艺

在文章【电子通识】半导体工艺——光刻工艺中我们讲到人们经常将 Photo Lithography&#xff08;光刻&#xff09;缩写成 Photo。光刻工艺是在晶圆上利用光线来照射带有电路图形的光罩&#xff0c;从而绘制电路。光刻工艺类似于洗印黑白照片&#xff0c;将在胶片上形成的图像印…

opencv之图像梯度

图像梯度 图像梯度计算的是图像变化的速度。对于图像的边缘部分&#xff0c;其灰度值变化较大&#xff0c;梯度值也较大&#xff1b;相反&#xff0c;对于图像中比较平滑的部分&#xff0c;其灰度值变化较小&#xff0c;相应的梯度值也较小。一般情况下&#xff0c;图像梯度计…

首批通过!华为云CodeArts Snap智能开发助手通过可信AI智能编码工具评估,获当前最高等级

近日&#xff0c;华为云CodeArts Snap智能开发助手在中国信通院组织的智能编码工具首轮评估中&#xff0c;最终获得4级评级, 成为国内首批通过该项评估并获得当前最高评级的企业之一。 此次评估以《智能化软件工程技术和应用要求 第2部分&#xff1a;智能开发能力》为依据&…

ubuntu 20.04 一直卡在登录界面,即使密码正确也无法登录(失败记录)

ubuntu 20.04 一直卡在登录界面&#xff0c;即使密码正确也无法登录 这次是装实体机&#xff0c;一次失败的尝试。。。 名称型号CPUIntel Xeon E5-2673 V3GPURTX 3060 mobile 安装的时候不要选install third-party software for graphics and Wi-fi hardware and additional …

Leetcode面试经典150题-55.跳跃游戏

解法都在代码里&#xff0c;不懂就留言或者私信 class Solution {public boolean canJump(int[] nums) {/**如果就一个位置&#xff0c;你本来就在这&#xff0c;肯定可以跳到*/if(nums.length 1) {return true;}/**这个题的解题思路是遍历数组&#xff0c;如果当前位置不在之…

每日OJ_牛客_数组中出现次数超过一半的数字

目录 牛客_数组中出现次数超过一半的数字 解析代码1 解析代码2 牛客_数组中出现次数超过一半的数字 数组中出现次数超过一半的数字__牛客网 给一个长度为 n 的数组&#xff0c;数组中有一个数字出现的次数超过数组长度的一半&#xff0c;请找出这个数字。例如输入一个长度为…

RP2040 C SDK clocks时钟源配置使用

RP2040 C SDK clocks时钟源配置使用 &#x1f33f;RP2040时钟源API函数文档&#xff1a;https://www.raspberrypi.com/documentation/pico-sdk/hardware.html#group_hardware_clocks &#x1f341;RP2040时钟树&#xff1a; 系统时钟源可以来自外部时钟输入&#xff08;exte…

程序员如何写笔记并整理资料?

整理笔记 word。没错&#xff0c;我也看了网上一大堆软件&#xff0c;还有git管理等等。个人认为如果笔记只是记录个人的经验积累&#xff0c;一个word就够了&#xff0c;那些notepad&#xff0c;laTex个人觉得不够简练。word。 1.word可以插入任何文件附件(目前最大的word 20…

9.9(QT Day 2)

将day1做的登录界面升级优化【资源文件的添加】 在登录界面的登录取消按钮进行以下设置&#xff1a; 使用手动连接&#xff0c;将登录框中的取消按钮使用第2种方式的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函数 将登录按钮使用qt4版本的连接到自定义…

面试题复习(0902-0909)

1. 完全背包问题 和01背包唯一的区别是&#xff0c;每件物品都有无限个&#xff08;也就是可以放入背包多次&#xff09; 代码和01唯一的区别在于j的循环是从小到大&#xff0c;不是从大到小。ij谁在外谁在内层区别不大。 #include <bits/stdc.h> using namespace std…

国产化数据库挑战及发展趋势

非国产数据库如Oracle、MySQL和MSSQL等在某些领域占据重要地位&#xff0c;但国产数据库的市场份额正在逐步提升&#xff0c;特别是在政策支持和市场需求的双重推动下&#xff0c;国产数据库的替代进程正在加速。 一、国产数据库市场规模 2024年中国数据库市场规模预计为543.1亿…

【树和二叉树的相关定义】概念

1.回顾与概览 2.什么是树型结构 3.树的&#xff08;递归&#xff09;定义与基本术语 3.1树的定义 注意&#xff1a;除了根结点以外&#xff0c;任何一个结点都有且仅有一个前驱 3.2树的其他表示方式 3.3树的基本术语 结点&#xff1a;数据元素以及指向子树的分支根结点:非空…

AI基础 L16 Logic Agents I

What is an Agent? • The main point about agents is they are autonomous: capable of acting independently, exhibiting control over their internal state • Thus: an agent is a computer system capable of autonomous action in some environment in order to mee…

JavaFX应用更新检测功能(在线自动更新方案)

JavaFX开发的桌面应用属于C端&#xff0c;一般来说需要版本检测和自动更新功能&#xff0c;这里记录一下一种版本检测和自动更新的方法。 1. 整体方案 JavaFX.应用版本检测、自动更新主要涉及一下步骤&#xff1a; 读取本地应用版本拉取远程版本并比较两个版本如果需要升级&…

手机TF卡格式化后数据恢复:方法、挑战与预防措施

在现代生活中&#xff0c;‌手机已经成为我们不可或缺的一部分&#xff0c;‌而TF卡&#xff08;‌即MicroSD卡&#xff09;‌作为手机存储的扩展&#xff0c;‌更是承载了我们大量的重要数据。‌然而&#xff0c;‌不慎的格式化操作往往导致数据丢失&#xff0c;‌给用户带来不…

【重学 MySQL】五、MySQL 的卸载

【重学 MySQL】五、MySQL 的卸载 停止MySQL服务卸载MySQL程序删除残余文件清理注册表删除环境变量配置重启电脑 MySQL的卸载过程需要仔细操作&#xff0c;以确保彻底卸载并清理所有相关文件和配置。 停止MySQL服务 打开任务管理器&#xff1a;右键点击任务栏空白处&#xff0…