当前位置: 首页 > news >正文

迭代器模式及优化

迭代器模式(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.xdnf.cn/news/1310005.html

相关文章:

  • 模式匹配自动机全面理论分析
  • 【Web后端】Django、flask及其场景——以构建系统原型为例
  • AI 搜索时代:引领变革,重塑您的 SEO 战略
  • 基于uni-app+vue3实现的微信小程序地图范围限制与单点标记功能实现指南
  • Matplotlib直线绘制:从基础到三维空间的高级可视化
  • 数组名本质与指针运算揭秘
  • List容器:特性与操作使用指南
  • 零基础学习人工智能的完整路线规划
  • 民法学学习笔记(个人向) Part.5
  • 学习游戏制作记录(制作系统与物品掉落系统)8.16
  • MySQL查询性能慢时索引失效的排查与优化实践
  • Redis缓存
  • 【OpenGL】LearnOpenGL学习笔记09 - 材质、光照贴图
  • 登录与登录校验:Web安全核心解析
  • 【昇腾】单张48G Atlas 300I Duo推理卡MindIE+WebUI方式跑7B大语言模型_20250816
  • 如何在FastAPI中玩转APScheduler,实现动态定时任务的魔法?
  • 【wmi异常】关于taskkill命令提示“错误:找不到” 以及无法正常获取设备机器码的处理办法
  • pytorch例子计算两张图相似度
  • PHP反序列化的CTF题目环境和做题复现第2集_POP链构造
  • 利用Qwen大模型进行c++11并发库的学习,与时俱进!!!!
  • AI安全增强核心技术:提示词防火墙、置信度过滤与知识蒸馏防御
  • 第6问 数据分析领域主要的岗位有哪些?
  • Rust 入门 KV存储HashMap (十七)
  • pdf合并代码
  • 【C++】异常详解(万字解读)
  • FPGA串口通信实现方案
  • Qt QDateTime时间部分显示为全0,QTime赋值后显示无效问题【已解决】
  • 【C++】C++11
  • Maven私服配置模版
  • 深入详解PCB布局布线技巧-去耦电容的摆放位置