迭代器模式及优化

迭代器模式(Iterator Pattern)是一种行为型设计模式,用于提供一种统一的方式遍历聚合对象(如集合、容器)中的元素,而无需暴露对象的内部实现细节。它将遍历逻辑与聚合对象分离,使得遍历操作可以独立于聚合结构变化,同时支持对同一聚合对象进行多种不同的遍历方式。

一、介绍

核心角色

迭代器模式包含4个关键角色:

  1. 迭代器(Iterator)
    定义遍历元素的接口,通常包含 hasNext()(是否有下一个元素)、next()(获取下一个元素)等方法。
  2. 具体迭代器(ConcreteIterator)
    实现迭代器接口,负责管理遍历的当前位置,记录遍历状态。
  3. 聚合(Aggregate)
    定义创建迭代器的接口(通常是 createIterator() 方法),充当迭代器的工厂。
  4. 具体聚合(ConcreteAggregate)
    实现聚合接口,返回具体迭代器实例,同时维护元素的存储结构(如数组、链表等)。
优点
  1. 封装性好:客户端无需知道聚合对象的内部结构(如数组、链表),只需通过迭代器接口遍历。
  2. 单一职责:聚合对象专注于存储数据,迭代器专注于遍历逻辑,符合单一职责原则。
  3. 扩展性强:新增遍历方式只需添加新的迭代器类,无需修改聚合对象(符合开闭原则)。
  4. 统一接口:不同聚合对象可以提供相同的迭代器接口,客户端可以用一致的代码遍历不同容器。
适用场景

迭代器模式适用于以下场景:

  1. 需要遍历聚合对象但不暴露其内部结构
    如遍历链表、树、哈希表等,客户端无需知道元素的存储方式。
  2. 需要为同一聚合对象提供多种遍历方式
    如正序遍历、倒序遍历、过滤遍历(只遍历满足条件的元素)。
  3. 需要统一不同聚合对象的遍历接口
    如让数组、链表、栈等不同容器使用相同的遍历方式(如STL中的begin()/end())。
  4. 遍历逻辑复杂,需要与聚合对象分离
    将遍历代码从聚合类中抽离,降低类的复杂度。

二、实现

以图书库为例,展示如何使用迭代器模式遍历不同类型的书架:

#include <iostream>
#include <vector>
#include <string>
#include <memory>
#include <stdexcept>// 前向声明
template <typename T>
class Iterator;// 抽象聚合类:定义创建迭代器的接口
template <typename T>
class Aggregate {
public:virtual ~Aggregate() = default;virtual std::unique_ptr<Iterator<T>> createIterator() = 0;virtual void add(const T& item) = 0;virtual size_t size() const = 0;virtual T get(size_t index) const = 0;
};// 抽象迭代器类:定义遍历接口
template <typename T>
class Iterator {
public:virtual ~Iterator() = default;virtual bool hasNext() const = 0;virtual T next() = 0;virtual void reset() = 0;
};// 具体聚合:书架(使用数组存储)
class BookShelf : public Aggregate<std::string> {
private:std::vector<std::string> books_;public:void add(const std::string& book) override {books_.push_back(book);}size_t size() const override {return books_.size();}std::string get(size_t index) const override {if (index >= books_.size()) {throw std::out_of_range("索引超出范围");}return books_[index];}// 创建数组迭代器std::unique_ptr<Iterator<std::string>> createIterator() override;
};// 具体迭代器:书架迭代器(数组遍历)
class BookShelfIterator : public Iterator<std::string> {
private:const BookShelf& shelf_;size_t currentIndex_;public:explicit BookShelfIterator(const BookShelf& shelf) : shelf_(shelf), currentIndex_(0) {}bool hasNext() const override {return currentIndex_ < shelf_.size();}std::string next() override {if (!hasNext()) {throw std::out_of_range("没有更多书籍");}return shelf_.get(currentIndex_++);}void reset() override {currentIndex_ = 0;}
};// 实现书架的迭代器创建方法
std::unique_ptr<Iterator<std::string>> BookShelf::createIterator() {return std::make_unique<BookShelfIterator>(*this);
}// 具体聚合:环形书架(循环遍历)
class CircularBookShelf : public Aggregate<std::string> {
private:std::vector<std::string> books_;public:void add(const std::string& book) override {books_.push_back(book);}size_t size() const override {return books_.size();}std::string get(size_t index) const override {if (books_.empty()) {throw std::runtime_error("书架为空");}// 环形索引(取模运算实现循环)return books_[index % books_.size()];}// 创建环形迭代器std::unique_ptr<Iterator<std::string>> createIterator() override;
};// 具体迭代器:环形迭代器(支持循环遍历)
class CircularIterator : public Iterator<std::string> {
private:const CircularBookShelf& shelf_;size_t currentIndex_;size_t maxSteps_;  // 最大遍历步数(避免无限循环)public:explicit CircularIterator(const CircularBookShelf& shelf, size_t maxSteps = 10): shelf_(shelf), currentIndex_(0), maxSteps_(maxSteps) {}bool hasNext() const override {return currentIndex_ < maxSteps_ && !shelf_.size() == 0;}std::string next() override {if (!hasNext()) {throw std::out_of_range("已达到最大遍历步数");}return shelf_.get(currentIndex_++);}void reset() override {currentIndex_ = 0;}
};// 实现环形书架的迭代器创建方法
std::unique_ptr<Iterator<std::string>> CircularBookShelf::createIterator() {return std::make_unique<CircularIterator>(*this);
}// 客户端代码:统一遍历不同类型的书架
void printBooks(Iterator<std::string>& iterator) {while (iterator.hasNext()) {std::cout << "- " << iterator.next() << std::endl;}
}int main() {// 普通书架BookShelf normalShelf;normalShelf.add("《设计模式》");normalShelf.add("《C++ Primer》");normalShelf.add("《算法导论》");std::cout << "普通书架的书籍:" << std::endl;auto normalIterator = normalShelf.createIterator();printBooks(*normalIterator);// 环形书架CircularBookShelf circularShelf;circularShelf.add("《红楼梦》");circularShelf.add("《西游记》");circularShelf.add("《三国演义》");std::cout << "\n环形书架的书籍(循环遍历5本):" << std::endl;auto circularIterator = circularShelf.createIterator();printBooks(*circularIterator);return 0;
} 
输出结果
普通书架的书籍:
- 《设计模式》
- 《C++ Primer》
- 《算法导论》环形书架的书籍(循环遍历5本):
- 《红楼梦》
- 《西游记》
- 《三国演义》
- 《红楼梦》
- 《西游记》
应用场景
  1. 容器类库
    • C++ STL、Java Collections Framework等都广泛使用迭代器模式
    • std::vector<int>::iteratorlist.iterator()
  2. 数据库操作
    • 数据库查询结果集(ResultSet)通过迭代器遍历记录
    • 支持游标移动、条件过滤等复杂遍历
  3. 树形结构遍历
    • 二叉树的前序、中序、后序遍历可通过不同迭代器实现
    • XML/JSON文档解析中的节点遍历
  4. 流处理
    • 输入流、输出流的内容读取(如std::istream_iterator
    • 日志文件的逐行读取
  5. UI组件遍历
    • 界面控件树的遍历(如遍历所有按钮并设置属性)
    • 菜单层级结构的遍历

三、优化

优化点
  1. STL风格迭代器
    • 实现了符合STL标准的迭代器接口,包含operator*operator++等必要操作符
    • 定义了正确的迭代器分类(forward_iterator_tagbidirectional_iterator_tag
    • 支持begin()/end()rbegin()/rend()接口,与STL容器用法一致
  2. 范围for循环支持
    • 通过实现begin()end()方法,使自定义容器支持C++11的范围for循环
    • 客户端代码可以像遍历vector一样遍历自定义书架:for (const auto& book : shelf)
  3. 迭代器扩展
    • 增加了反向迭代器(ReverseIterator),支持从后向前遍历
    • 实现了筛选迭代器(FilteredIterator),支持按条件过滤元素(结合了装饰器模式)
  4. 类型安全与封装
    • 使用const限定符确保常量正确性
    • 将迭代器作为内部类实现,增强封装性
    • 通过异常处理处理越界访问等错误情况
  5. 数据模型完善
    • 引入Book类封装实际数据,使示例更贴近真实场景
    • Book类实现operator<<,方便打印输出
#include <iostream>
#include <vector>
#include <string>
#include <memory>
#include <stdexcept>
#include <algorithm>
#include <iterator>// 1. 书籍类(存储实际数据)
class Book {
private:std::string title_;std::string author_;public:Book(std::string title, std::string author): title_(std::move(title)), author_(std::move(author)) {}const std::string& getTitle() const { return title_; }const std::string& getAuthor() const { return author_; }// 重载输出运算符,方便打印friend std::ostream& operator<<(std::ostream& os, const Book& book) {return os << "\"" << book.title_ << "\" by " << book.author_;}
};// 2. 抽象书架类(聚合接口)
class BookShelf {
public:virtual ~BookShelf() = default;virtual void add(const Book& book) = 0;virtual size_t size() const = 0;virtual const Book& get(size_t index) const = 0;// STL风格迭代器接口class Iterator {public:using iterator_category = std::forward_iterator_tag;using value_type = const Book;using difference_type = std::ptrdiff_t;using pointer = const Book*;using reference = const Book&;Iterator(const BookShelf& shelf, size_t index): shelf_(shelf), index_(index) {}reference operator*() const {return shelf_.get(index_);}pointer operator->() const {return &shelf_.get(index_);}Iterator& operator++() {if (index_ < shelf_.size()) {++index_;}return *this;}Iterator operator++(int) {Iterator temp = *this;++(*this);return temp;}bool operator==(const Iterator& other) const {return &shelf_ == &other.shelf_ && index_ == other.index_;}bool operator!=(const Iterator& other) const {return !(*this == other);}private:const BookShelf& shelf_;size_t index_;};// 反向迭代器class ReverseIterator {public:using iterator_category = std::bidirectional_iterator_tag;using value_type = const Book;using difference_type = std::ptrdiff_t;using pointer = const Book*;using reference = const Book&;ReverseIterator(const BookShelf& shelf, size_t index): shelf_(shelf), index_(index) {}reference operator*() const {return shelf_.get(index_);}pointer operator->() const {return &shelf_.get(index_);}ReverseIterator& operator++() {if (index_ > 0) {--index_;} else {index_ = shelf_.size(); // 标记为结束}return *this;}ReverseIterator operator++(int) {ReverseIterator temp = *this;++(*this);return temp;}bool operator==(const ReverseIterator& other) const {return &shelf_ == &other.shelf_ && index_ == other.index_;}bool operator!=(const ReverseIterator& other) const {return !(*this == other);}private:const BookShelf& shelf_;size_t index_;};// 迭代器范围接口(支持范围for循环)Iterator begin() const { return Iterator(*this, 0); }Iterator end() const { return Iterator(*this, size()); }ReverseIterator rbegin() const { return size() > 0 ? ReverseIterator(*this, size() - 1) : rend(); }ReverseIterator rend() const { return ReverseIterator(*this, size()); }
};// 3. 具体聚合:线性书架
class LinearBookShelf : public BookShelf {
private:std::vector<Book> books_;public:void add(const Book& book) override {books_.push_back(book);}size_t size() const override {return books_.size();}const Book& get(size_t index) const override {if (index >= books_.size()) {throw std::out_of_range("索引超出范围");}return books_[index];}
};// 4. 具体聚合:环形书架(循环迭代)
class CircularBookShelf : public BookShelf {
private:std::vector<Book> books_;size_t maxIterations_; // 最大迭代次数(避免无限循环)public:explicit CircularBookShelf(size_t maxIterations = 2): maxIterations_(maxIterations) {}void add(const Book& book) override {books_.push_back(book);}size_t size() const override {return books_.empty() ? 0 : books_.size() * maxIterations_;}const Book& get(size_t index) const override {if (books_.empty()) {throw std::runtime_error("书架为空");}// 环形索引计算return books_[index % books_.size()];}
};// 5. 筛选迭代器(装饰器模式扩展)
class FilteredIterator {
private:BookShelf::Iterator it_;BookShelf::Iterator end_;std::function<bool(const Book&)> predicate_;// 找到下一个符合条件的元素void findNext() {while (it_ != end_ && !predicate_(*it_)) {++it_;}}public:FilteredIterator(BookShelf::Iterator begin, BookShelf::Iterator end,std::function<bool(const Book&)> predicate): it_(begin), end_(end), predicate_(std::move(predicate)) {findNext();}const Book& operator*() const {if (it_ == end_) {throw std::out_of_range("没有符合条件的元素");}return *it_;}FilteredIterator& operator++() {if (it_ != end_) {++it_;findNext();}return *this;}bool operator!=(const FilteredIterator& other) const {return it_ != other.it_;}
};// 筛选迭代器的范围包装
struct FilteredRange {BookShelf::Iterator begin_;BookShelf::Iterator end_;std::function<bool(const Book&)> predicate_;FilteredIterator begin() const {return FilteredIterator(begin_, end_, predicate_);}FilteredIterator end() const {return FilteredIterator(end_, end_, predicate_);}
};// 创建筛选范围的辅助函数
FilteredRange filter(const BookShelf& shelf, std::function<bool(const Book&)> predicate) {return {shelf.begin(), shelf.end(), std::move(predicate)};
}// 客户端代码
int main() {// 创建线性书架并添加书籍LinearBookShelf linearShelf;linearShelf.add(Book("设计模式", " Erich Gamma"));linearShelf.add(Book("C++ Primer", "Stanley Lippman"));linearShelf.add(Book("算法导论", "Thomas H. Cormen"));linearShelf.add(Book("C++ 并发编程", "Anthony Williams"));std::cout << "=== 线性书架(正向遍历) ===" << std::endl;for (const auto& book : linearShelf) {std::cout << "- " << book << std::endl;}std::cout << "\n=== 线性书架(反向遍历) ===" << std::endl;for (auto it = linearShelf.rbegin(); it != linearShelf.rend(); ++it) {std::cout << "- " << *it << std::endl;}// 创建环形书架CircularBookShelf circularShelf(2); // 循环2次circularShelf.add(Book("红楼梦", "曹雪芹"));circularShelf.add(Book("西游记", "吴承恩"));circularShelf.add(Book("三国演义", "罗贯中"));std::cout << "\n=== 环形书架(循环遍历) ===" << std::endl;for (const auto& book : circularShelf) {std::cout << "- " << book << std::endl;}// 筛选迭代器示例:只显示C++相关书籍std::cout << "\n=== 筛选C++相关书籍 ===" << std::endl;auto cppBooks = filter(linearShelf, [](const Book& book) {return book.getTitle().find("C++") != std::string::npos;});for (const auto& book : cppBooks) {std::cout << "- " << book << std::endl;}return 0;
} 
输出结果
=== 线性书架(正向遍历) ===
- "设计模式" by  Erich Gamma
- "C++ Primer" by Stanley Lippman
- "算法导论" by Thomas H. Cormen
- "C++ 并发编程" by Anthony Williams=== 线性书架(反向遍历) ===
- "C++ 并发编程" by Anthony Williams
- "算法导论" by Thomas H. Cormen
- "C++ Primer" by Stanley Lippman
- "设计模式" by  Erich Gamma=== 环形书架(循环遍历) ===
- "红楼梦" by 曹雪芹
- "西游记" by 吴承恩
- "三国演义" by 罗贯中
- "红楼梦" by 曹雪芹
- "西游记" by 吴承恩
- "三国演义" by 罗贯中=== 筛选C++相关书籍 ===
- "C++ Primer" by Stanley Lippman
- "C++ 并发编程" by Anthony Williams
优化后优势
  1. 与STL生态兼容
    • 可以使用STL算法库中的函数(如std::for_eachstd::find)操作自定义容器
    • 开发者无需学习新的迭代器用法,降低学习成本
  2. 使用便捷性提升
    • 范围for循环使遍历代码更简洁易读
    • 反向迭代器和筛选迭代器提供了更丰富的遍历方式
  3. 扩展性更强
    • 可以轻松添加新的迭代器类型(如随机访问迭代器、深度优先迭代器)
    • 筛选迭代器展示了如何通过组合模式扩展迭代器功能
  4. 更符合现代C++规范
    • 使用智能指针管理资源,避免内存泄漏
    • 利用lambda表达式实现灵活的筛选条件
    • 常量迭代器确保数据访问的const正确性

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

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

相关文章

纯Qt手撕gb28181协议/gb28181协议服务端/gb28181协议设备端/gb28181设备模拟器/gb28181虚拟监控设备

一、前言说明 搞完onvif设备模拟器&#xff0c;总想着把28181设备模拟也实现&#xff0c;因为之前已经花了大力气把28181平台软件端实现了&#xff0c;为了实现这个组件&#xff0c;头发掉了一大把&#xff0c;专门把国标文档看了好几遍&#xff0c;逐行阅读&#xff0c;针对需…

【渗透实战】无下载器环境(curl/wget)下玩转 Metasploit 自动利用

1. 背景与问题场景 在渗透测试或漏洞利用中&#xff0c;Metasploit&#xff08;MSF&#xff09;是业界最常用的框架之一。 其许多 RCE&#xff08;远程代码执行&#xff09;模块在落地 payload&#xff08;如 Meterpreter 或反弹 shell&#xff09;时&#xff0c;采用了 CMD St…

jd-hotkey探测热点key

对任意突发性的无法预先感知的热点数据&#xff0c;包括并不限于热点数据&#xff08;如突发大量请求同一个商品&#xff09;、热用户&#xff08;如恶意爬虫刷子&#xff09;、热接口&#xff08;突发海量请求同一个接口&#xff09;等&#xff0c;进行毫秒级精准探测到。然后…

C#WPF实战出真汁07--【系统设置】--菜品类型设置

1、菜品设置介绍 菜品设置跟餐桌设置的功能目的是相同的&#xff0c;包括了新增&#xff0c;删除&#xff0c;编辑&#xff0c;分页&#xff0c;查询&#xff0c;重置&#xff0c;全选&#xff0c;全消&#xff0c;列表功能&#xff0c;实现流程也是布局设计&#xff0c;后台逻…

aave v3 存款与借款利息的计算方式

本文只涉及到利率计算的数学原理&#xff0c;不作源码解析:存款首先我们假设小明在aave里面存了10000usdt&#xff0c;存的时候年化收益率是5%,那么半年后其存款的利息是多少呢?常规的计算方式如下:利息10000*5%*(存款的时长/一年的时长)这么做有什么问题呢&#xff1f;假设现…

Windows MCP.Net:基于.NET的Windows桌面自动化MCP服务器深度解析

&#x1f4cb; 目录 项目概述 技术架构深度解析 核心功能模块详解 代码实现分析 使用场景与实战案例 性能优化与最佳实践 扩展开发指南 总结与展望 项目概述 什么是Windows-MCP.Net&#xff1f; Windows MCP.Net是一个基于.NET 10.0开发的Windows桌面自动化MCP&…

Boost.Asio学习(7):Boost.Beast实现简易http服务器

namespace beast boost::beast;beast::flat_buffer是一个用于 Boost.Asio 和 Boost.Beast 网络读写的缓冲区实现。专为 一次性顺序读取 / 消费 场景设计&#xff0c;比 std::string 或 std::vector 高效&#xff0c;因为它是扁平内存结构&#xff08;contiguous memory&#x…

深入解析JVM内存区域划分:从理论到实践

Java虚拟机&#xff08;JVM&#xff09;是Java程序运行的核心环境&#xff0c;它负责管理内存分配、垃圾回收、字节码执行等关键任务。理解JVM的内存区域划分&#xff0c;对于优化Java应用性能、排查内存问题&#xff08;如OutOfMemoryError、StackOverflowError&#xff09;至…

滑窗|贪心|✅滚动数组

lc17.08pair按身高升序、相同时体重降序排序结果是找体重序列的最长递增子序列长度核心&#xff1a;转化为二维最长递增子序列问题求解vector<int> dp;for (auto& p : hw) {int w p.second;auto it lower_bound(dp.begin(), dp.end(), w);if (it dp.end()) {dp.pu…

深入理解数据库架构:从原理到实践的完整指南

一、数据库存储架构的多维度分类体系 1.1 基于数据组织方式的存储架构分类 数据库的存储架构从根本上决定了其性能特征、适用场景和扩展能力。理解不同的数据组织方式是选择合适数据库技术的基础&#xff0c;这种分类不仅反映了技术实现的差异&#xff0c;更体现了对不同业务需…

体彩排列三第2025218期号码分析

大家好&#xff0c;本人蔡楚门来此平台分享一下本期得经验和思路&#xff0c;希望能够给大家带来好的运气和灵感&#xff01;体彩排列三第2025218期号码分析&#xff0c;大小号码数字分析&#xff0c;上期开出全小号码最多&#xff0c;最近两期的开奖号码全部都是全小号码最多&…

java设计模式之迪米特法则介绍与说明

一、核心概念与目标 基本定义 迪米特法则的核心思想是&#xff1a;一个对象应该对其他对象尽可能少地了解&#xff0c;仅与直接关联的对象&#xff08;即“朋友”&#xff09;通信&#xff0c;避免与“陌生人”产生直接交互。 直接朋友&#xff1a;包括当前对象的成员变量、方法…

2024-2025华为ICT大赛中国区 实践赛昇腾AI赛道(高职组)全国总决赛 理论部分真题+解析

Part 1 昇腾AI全栈系统模块(共6题)&#xff1a;1、许多计算芯片可以设计作为人工智能的计算芯片&#xff0c;但不同的芯片计算性能不同&#xff0c;昇腾计算芯片是一种()芯片。(单选题)A.CPU B.GPU C. NPU D.TPU正确答案&#xff1a;C解析&#xff1a;A项CPU中央处理器的架…

网络安全和基础设施安全局 (CISA) 表示微分段不再是可选的

网络安全和基础设施安全局 (CISA) 最近发布了一系列指导文件中的第一份&#xff0c;旨在帮助联邦机构实施微分段&#xff0c;作为其零信任架构 (ZTA) 战略的一部分&#xff0c;以遵守2022 年白宫的授权。 该文件《零信任中的微分段&#xff0c;第一部分&#xff1a;介绍和规划…

Spring Boot SseEmitter 重复请求问题深度分析与解决方案

1. 前言 在使用 Spring Boot 开发流式接口(Server-Sent Events)时,我们遇到了一个令人困惑的问题:每次 SseEmitter 完成后,都会触发第二次请求,导致重复请求检测机制误报。本文将详细记录问题的发现、分析过程以及最终的解决方案。 2. 系统架构背景 2.1 请求处理架构 …

心路历程-三个了解敲开linux的大门

学习前都爱唠叨一番&#xff1a; 了解一下&#xff1a;互联网的发展是离不开服务器的&#xff0c;而服务器的系统主流的还是Linux&#xff1b;这个是有数据进行支撑的&#xff1b;这个只是作为了解而已&#xff0c;我们并不买课&#xff0c;也不做什么买卖的行为&#xff0c;仅…

关于“双指针法“的总结

笔者这些天终于达成了只狼的全成就&#xff0c;甚是欢喜。然而乐极生悲&#xff0c;最近做了些算法题&#xff0c;竟没有一道靠自己做出来。感觉算法题常常用到“双指针法”呢……为什么到现在我还是做不出来这些算法题……今天就来试着总结一下它的使用场景吧。快慢指针法又名…

基于51单片机的智能吊灯

基于 51 单片机的智能吊灯设计与实现论文简纲一、引言1.1 研究背景与意义阐述传统照明设备在节能性、智能化方面的不足&#xff0c;结合智能家居产业发展趋势&#xff0c;说明设计基于 51 单片机的智能吊灯对提升生活便利性、降低能耗的现实意义。1.2 国内外研究现状简要介绍当…

CF每日三题(1500-1700)

1792C 逆向思维1036D 前缀和尺取1598D 组合数学取三元组 将二元组放在坐标系中更好找到规律 1792C 思维 1500 参考题解 正难则反 注意是对一个排列进行操作&#xff0c;最后还原成1,2,…,n 每次选两个数字很难想&#xff0c;反着想就是把1-n的排列变成所给数组的逆操作&#x…

Boost搜索引擎项目(详细思路版)

目录 项目相关背景 搜索引擎原理技术栈和项目环境 导入数据到自己的本地 数据去标签与数据清洗模块 Enumfile(src_path, &file_list)递归式写入 Parsehtml(file_list, &results)去标签 bool Parsetitle(const string& file, string* title)拆分标题 bool Pa…