文章目录

    • 一、概念
    • 二、实例分析
    • 三、示例代码

一、概念

  迭代器模式 是一种 行为型设计模式,用于在不暴露集合对象内部结构的前提下,顺序访问集合中的元素。

换句话说:

  • 集合类只负责数据存储;
  • 迭代器类负责遍历集合;
  • 使用者不需要关心集合内部是数组、链表还是树。

在这里插入图片描述

迭代器模式一般包含以下角色:

  1. Iterator(抽象迭代器):定义访问元素的接口,比如 first()、next()、hasNext()、currentItem()。
  2. ConcreteIterator(具体迭代器):实现 Iterator 接口,负责跟踪遍历位置。
  3. Aggregate(抽象聚合类):定义创建迭代器的接口。
  4. ConcreteAggregate(具体聚合类):实现 Aggregate,返回一个具体迭代器对象。

迭代器模式结构:
在这里插入图片描述

二、实例分析

问题:
集合是编程中最常使用的数据类型之一。 尽管如此, 集合只是一组对象的容器而已。
在这里插入图片描述
大部分集合使用简单列表存储元素。 但有些集合还会使用栈、 树、 图和其他复杂的数据结构。

无论集合的构成方式如何, 它都必须提供某种访问元素的方式, 便于其他代码使用其中的元素。 集合应提供一种能够遍历元素的方式, 且保证它不会周而复始地访问同一个元素。

如果你的集合基于列表, 那么这项工作听上去仿佛很简单。 但如何遍历复杂数据结构 (例如树) 中的元素呢? 例如, 今天你需要使用深度优先算法来遍历树结构, 明天可能会需要广度优先算法; 下周则可能会需要其他方式 (比如随机存取树中的元素)。

在这里插入图片描述
不断向集合中添加遍历算法会模糊其 “高效存储数据” 的主要职责。 此外, 有些算法可能是根据特定应用订制的, 将其加入泛型集合类中会显得非常奇怪。

另一方面, 使用多种集合的客户端代码可能并不关心存储数据的方式。 不过由于集合提供不同的元素访问方式, 你的代码将不得不与特定集合类进行耦合。

解决方案:
迭代器模式的主要思想是将集合的遍历行为抽取为单独的迭代器对象。
在这里插入图片描述
除实现自身算法外, 迭代器还封装了遍历操作的所有细节, 例如当前位置和末尾剩余元素的数量。 因此, 多个迭代器可以在相互独立的情况下同时访问集合。

迭代器通常会提供一个获取集合元素的基本方法。 客户端可不断调用该方法直至它不返回任何内容, 这意味着迭代器已经遍历了所有元素。

所有迭代器必须实现相同的接口。 这样一来, 只要有合适的迭代器, 客户端代码就能兼容任何类型的集合或遍历算法。 如果你需要采用特殊方式来遍历集合, 只需创建一个新的迭代器类即可, 无需对集合或客户端进行修改。

三、示例代码

示例一:

#include <iostream>
#include <vector>
#include <memory>
using namespace std;// 抽象迭代器
class Iterator {
public:virtual bool hasNext() = 0;virtual int next() = 0;virtual ~Iterator() = default;
};// 抽象聚合类
class Aggregate {
public:virtual unique_ptr<Iterator> createIterator() = 0;virtual ~Aggregate() = default;
};// 具体聚合类
class ConcreteAggregate : public Aggregate {
private:vector<int> items;
public:void add(int item) { items.push_back(item); }vector<int>& getItems() { return items; }unique_ptr<Iterator> createIterator() override;
};// 具体迭代器
class ConcreteIterator : public Iterator {
private:ConcreteAggregate& aggregate;size_t index = 0;
public:ConcreteIterator(ConcreteAggregate& agg) : aggregate(agg) {}bool hasNext() override {return index < aggregate.getItems().size();}int next() override {return aggregate.getItems()[index++];}
};// 工厂方法实现
unique_ptr<Iterator> ConcreteAggregate::createIterator() {return make_unique<ConcreteIterator>(*this);
}// 测试
int main() {ConcreteAggregate agg;agg.add(10);agg.add(20);agg.add(30);auto it = agg.createIterator();while (it->hasNext()) {cout << it->next() << " ";}return 0;
}

示例二:
在这里插入图片描述
上图展示的是一个社交网络遍历的迭代器模式实现,核心思想是:

  • SocialNetwork 定义了创建迭代器的接口(好友迭代器、同事迭代器)。
  • WeChat 是具体的社交网络实现,能返回具体迭代器。
  • ProfileIterator 是迭代器接口,统一规定 getNext() / hasMore()。
  • WeChatIterator 是具体的迭代器实现,负责按不同方式遍历好友或同事。
  • Application 只依赖 SocialNetwork 和 ProfileIterator 接口,不依赖具体实现。
#include <iostream>
#include <string>
#include <vector>
#include <memory>
using namespace std;// ==================== Profile ====================
class Profile {string id;string email;
public:Profile(string i, string e) : id(move(i)), email(move(e)) {}string getId() const { return id; }string getEmail() const { return email; }
};// ==================== 迭代器接口 ====================
class ProfileIterator {
public:virtual bool hasMore() = 0;virtual shared_ptr<Profile> getNext() = 0;virtual ~ProfileIterator() = default;
};// ==================== 社交网络接口 ====================
class SocialNetwork {
public:virtual unique_ptr<ProfileIterator> createFriendsIterator(const string& profileId) = 0;virtual unique_ptr<ProfileIterator> createCoworkersIterator(const string& profileId) = 0;virtual ~SocialNetwork() = default;
};// ==================== WeChat 迭代器 ====================
class WeChat; // 前向声明class WeChatIterator : public ProfileIterator {WeChat* weChat;string profileId;string type;  // friends / coworkerssize_t currentPosition = 0;vector<shared_ptr<Profile>> cache;public:WeChatIterator(WeChat* wc, string id, string t): weChat(wc), profileId(move(id)), type(move(t)) {lazyInit();}void lazyInit();bool hasMore() override {return currentPosition < cache.size();}shared_ptr<Profile> getNext() override {if (!hasMore()) return nullptr;return cache[currentPosition++];}
};// ==================== WeChat 网络实现 ====================
class WeChat : public SocialNetwork {vector<shared_ptr<Profile>> profiles;
public:void addProfile(shared_ptr<Profile> p) { profiles.push_back(p); }// 简单模拟:好友=所有偶数下标,同事=所有奇数下标vector<shared_ptr<Profile>> requestProfiles(const string& id, const string& type) {vector<shared_ptr<Profile>> result;for (size_t i = 0; i < profiles.size(); i++) {if ((type == "friends" && i % 2 == 0) ||(type == "coworkers" && i % 2 == 1)) {result.push_back(profiles[i]);}}return result;}unique_ptr<ProfileIterator> createFriendsIterator(const string& profileId) override {return make_unique<WeChatIterator>(this, profileId, "friends");}unique_ptr<ProfileIterator> createCoworkersIterator(const string& profileId) override {return make_unique<WeChatIterator>(this, profileId, "coworkers");}
};// WeChatIterator 延迟加载实现
void WeChatIterator::lazyInit() {if (cache.empty()) {cache = weChat->requestProfiles(profileId, type);}
}// ==================== 应用层(发垃圾消息) ====================
class SocialSpammer {
public:void send(ProfileIterator& it, const string& message) {while (it.hasMore()) {auto profile = it.getNext();cout << "Send '" << message << "' to " << profile->getEmail() << endl;}}
};class Application {SocialSpammer spammer;shared_ptr<SocialNetwork> network;
public:Application(shared_ptr<SocialNetwork> net) : network(move(net)) {}void sendSpamToFriends(const string& profileId) {auto it = network->createFriendsIterator(profileId);spammer.send(*it, "Hello Friend!");}void sendSpamToCoworkers(const string& profileId) {auto it = network->createCoworkersIterator(profileId);spammer.send(*it, "Hello Coworker!");}
};// ==================== 测试 ====================
int main() {auto wechat = make_shared<WeChat>();wechat->addProfile(make_shared<Profile>("001", "a@example.com"));wechat->addProfile(make_shared<Profile>("002", "b@example.com"));wechat->addProfile(make_shared<Profile>("003", "c@example.com"));wechat->addProfile(make_shared<Profile>("004", "d@example.com"));Application app(wechat);cout << "=== 发送给好友 ===" << endl;app.sendSpamToFriends("001");cout << "=== 发送给同事 ===" << endl;app.sendSpamToCoworkers("001");
}

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue 3 学习路线指南

阶段一:基础入门 (1-2周) 1.1 环境准备 # 安装 Node.js (推荐 18+ 版本) # 安装 Vue CLI 或使用 Vite npm create vue@latest my-vue-app cd my-vue-app npm install npm run dev1.2 Vue 3 核心概念 响应式系统:ref(), reactive(), computed() 组合式 API:setup() 函数 模…

使用 `hover:not-[:has(:hover)]` 避免「父元素和子元素同时 hover」时的样式冲突

:hover:not-(:has(:hover)) has() CSS 4 引入的“父选择器”&#xff0c;意思是&#xff1a;匹配那些里面包含某个子元素/状态的元素。 例如&#xff1a;:has(:hover) 表示「自身包含正在被 hover 的子元素」。 :not() 取反伪类&#xff0c;表示不匹配里面的条件。 比如我…

第三十天-DMA串口实验

一、DMA概述二、DMA通道注意&#xff0c;想要往串口中写数据&#xff0c;外部请求信号应该是USARTx_TX&#xff0c;当DR寄存器为空时&#xff0c;产生TX信号&#xff0c;请求DMA。反之&#xff0c;从串口中读数据&#xff0c;外部请求信号应该是USARTx_RX&#xff0c;当DR寄存器…

C/C++ 中的inline(内联函数关键字)详解

在 C/C 编程中&#xff0c;函数调用虽然带来了代码复用和可读性提升&#xff0c;但频繁调用小型函数可能会产生额外的调用开销&#xff08;call overhead&#xff09;&#xff0c;比如栈帧的建立与销毁、参数传递等。 为了减少这种开销&#xff0c;C 引入了 inline&#xff08;…

2025 年高教社杯全国大学生数学建模竞赛A 题 烟幕干扰弹的投放策略完整成品 思路 模型 代码 结果 全网首发高质量!!!

烟幕干扰弹主要通过化学燃烧或爆炸分散形成烟幕或气溶胶云团,在目标前方特定空域形成遮蔽&#xff0c;干扰敌方导弹&#xff0c;具有成本低、效费比高等优点。随着烟幕干扰技术的不断发展&#xff0c;现已有多种投放方式完成烟幕干扰弹的定点精确抛撒,即在抛撒前能精确控制烟幕…

嵌入式第四十五天(51单片机相关)

一.1.CPU、MPU、MCU、GPU&#xff1a; CPU&#xff08;中央处理器&#xff09;&#xff1a;计算机的核心部件&#xff0c;负责执行指令和处理数据。 MPU&#xff08;微处理器&#xff09;&#xff1a;通常指更通用的处理器&#xff0c;强调计算能力。 MCU&#xff08;微控制器&…

今天面了一个Java后端工程师,真的让我猛抬头

今天面了一个Java后端工程师,真的让我猛抬头啊. 现在面试不像传统的八股文面试,我更多问的都是项目场景相关的问题,但是都能回答的不错.这一点我还是很惊讶的。 不仅如此,她的技术也很扎实,对Java核心机制&#xff08;JVM、并发、集合等&#xff09;理解深入&#xff0c;回答…

拦截器和过滤器(理论+实操)

拦截器和过滤器 本文旨在夯实基础以及实战加深理解,目的是更深的理解以便掌握,希望能跟着动手敲一遍,绝对受益匪浅 在本文,我会先给出两者的区别(理论知识),随后是两者各自的实操实现 文章目录拦截器和过滤器什么是过滤器和拦截器?1.过滤器2.拦截器执行整体流程拦截器和过滤器…

HTB 赛季8靶场 - Guardian

各位好&#xff0c;最近我的kali崩掉了&#xff0c;崩掉了&#xff0c;建议大家避K 番茄C盘瘦身&#xff0c;这家伙修改了我的avrt.dll文件&#xff0c;导致virtualbox不接受我的avrt.dll文件的签名了&#xff0c;从而导致virtualbox的虚拟机环境全崩无法开机。弄了几天&#x…

Rust+slint实现一个登录demo

系列文章目录 文章目录系列文章目录前言一、为什么前端选择slint而不是Tauri或者其他GUI框架二、开发工具三、代码编写项目结构前端代码编写后端开发编写运行效果总结前言 本文章就是一个简单rust全栈编程的一个小小的示例供rust新手阅读学习。 一、为什么前端选择slint而不是…

2025前端面试题及答案(详细)

HTML5 的新特性有哪些&#xff1f;简约版本&#xff1a;“HTML5 新特性主要体现在六个方面&#xff1a; 第一&#xff0c;语义化标签&#xff0c;比如 header、footer、nav 等&#xff0c;让页面结构更清晰&#xff1b; 第二&#xff0c;表单增强&#xff0c;新增了 date、emai…

分词器详解(二)

&#x1f50d; 第2层&#xff1a;中等深度&#xff08;15分钟理解&#xff09; 1. 理论基础 1.1 BPE的数学原理 核心思想&#xff1a;通过迭代合并高频字符对构建词汇表 算法形式化&#xff1a; 初始化词汇表 V0{c1,c2,...,cn}V_0 \{c_1, c_2, ..., c_n\}V0​{c1​,c2​,...,c…

嵌入式学习 51单片机(3)

UART 概述通用异步收发器&#xff08;UART&#xff09;是一种全双工、串行、异步通信协议&#xff0c;常用于设备间数据传输。包含两根信号线&#xff1a;RXD&#xff08;接收信号线&#xff09;TXD&#xff08;发送信号线&#xff09;通信方式单工通信方向固定&#xff0c;仅支…

Redis AOF 持久化:银行的 “交易流水单” 管理逻辑

目录 一、AOF 的核心逻辑&#xff1a;“每笔交易都记流水” 二、AOF 的三个步骤&#xff1a;从 “临时记录” 到 “正式归档” 1. 命令追加&#xff1a;记到 “临时小本本” 2. 写入与同步&#xff1a;抄到 “正式流水册” 3. AOF 还原&#xff1a;拿 “流水册” 重放交易…

代码随想录训练营第三十天|LeetCode452.用最少数量的箭引爆气球、LeetCode435.无重叠空间、LeetCode763.划分字母空间

452.用最少数量的箭引爆气球 贪心算法 重合最多的气球射一箭&#xff0c;就是局部用箭数量最少的&#xff0c;全局的用箭数量就是最少的。 首先对二维数组进行排序&#xff0c;这样就可以让气球更加紧凑。 思路&#xff1a;当前气球是否和上一个气球区间重合&#xff0c;如…

数据库事务隔离级别与 MVCC 机制详解

最近在准备面试&#xff0c;正把平时积累的笔记、项目中遇到的问题与解决方案、对核心原理的理解&#xff0c;以及高频业务场景的应对策略系统梳理一遍&#xff0c;既能加深记忆&#xff0c;也能让知识体系更扎实&#xff0c;供大家参考&#xff0c;欢迎讨论。在数据库并发操作…

【Cursor-Gpt-5-high】StackCube-v1 任务训练结果不稳定性的分析

1. Prompt 我是机器人RL方向的博士生正在学习ManiSkill&#xff0c;在学习时我尝试使用相同命令训练同一个任务&#xff0c;但是我发现最终的 success_once 指标并不是相同的&#xff0c;我感到十分焦虑&#xff0c; 我使用的命令如下&#xff1a; python sac.py --env_id"…

文档权限设置不合理会带来哪些问题

文档权限设置不合理会导致信息泄露、合规风险、协作效率下降、责任难以追溯、知识资产流失、员工信任受损、管理成本增加、企业战略受阻。这些问题不仅影响日常运营&#xff0c;更会对企业的长远发展构成威胁。根据IBM《2024数据泄露成本报告》&#xff0c;全球企业因数据泄露的…

Linux网络服务——基础设置

网络服务命令1.ping命令作用&#xff1a;测试网络连通性&#xff08;使用icmp协议&#xff09;常见选项&#xff1a;-c&#xff1a;指定ping的次数&#xff0c;默认无限次-I&#xff1a;指定发送请求的网卡[rootlocalhost ~]# ping 192.168.77.78 -c 4 -I ens160 PING 192.168.…

【multisim汽车尾灯设计】2022-12-1

缘由multisim汽车尾灯设计-学习和成长-CSDN问答 为什么模仿别人做的运行没啥效果&#xff0c;啥也看不明白&#xff0c;数字电子技术要做的任务。