C++ 迭代器模式(Iterator Pattern)
一、模式基础概述
1.1 定义
迭代器模式属于行为型设计模式 ,提供统一遍历接口,以顺序方式访问聚合容器内所有元素,全程不对外暴露容器内部存储结构、数据组织形式。将遍历逻辑与容器存储逻辑解耦,遵循单一职责原则。
1.2 核心思想
剥离集合自身的遍历行为,单独封装迭代器对象负责元素访问;客户端仅通过标准接口遍历数据,无需关心底层是数组、链表、树形等存储结构。
1.3 设计原则
- 单一职责:容器负责数据存储增删,迭代器负责遍历访问
- 迪米特法则:隐藏内部结构,降低外部与容器耦合度
- 开闭原则:新增遍历方式只需新增迭代器,不改动容器代码
二、核心组成角色
| 角色名称 | 核心职责 | C++ 实现形式 |
|---|---|---|
| 抽象迭代器 Iterator | 声明通用遍历接口,判断是否存在下一元素、获取当前元素 | 抽象模板基类,纯虚函数定义接口 |
| 具体迭代器 ConcreteIterator | 实现遍历接口,记录遍历游标位置,关联聚合容器,完成实际遍历 | 继承抽象迭代器,重写遍历方法 |
| 抽象聚合容器 Aggregate | 定义创建迭代器的统一接口,规范容器基础操作 | 抽象基类,声明创建迭代器函数 |
| 具体聚合容器 ConcreteAggregate | 存储实际元素,实现创建迭代器方法,提供元素查询、新增能力 | 继承抽象聚合,内部维护数据集合 |
| 客户端 Client | 通过迭代器遍历元素,调用标准接口完成访问 | 业务调用代码、主函数 |
三、模式运行流程
- 客户端创建具体聚合容器,并向容器添加业务元素
- 调用容器接口生成专属迭代器实例
- 客户端循环调用迭代器判断接口,校验是否还有未遍历元素
- 存在元素则获取当前元素,并移动遍历游标
- 遍历结束后终止访问,整个过程不直接操作容器内部数据
四、经典业务示例:书架书籍遍历
cpp
#include <iostream>
#include <vector>
#include <string>
#include <memory>
// 元素实体:书籍
class Book
{
private:
std::string bookName;
public:
Book(std::string name) : bookName(std::move(name)) {}
std::string getName() const
{
return bookName;
}
};
// 抽象迭代器模板
template<typename T>
class Iterator
{
public:
virtual ~Iterator() = default;
virtual bool hasNext() const = 0;
virtual T next() = 0;
};
// 抽象聚合容器模板
template<typename T>
class Aggregate
{
public:
virtual ~Aggregate() = default;
virtual std::unique_ptr<Iterator<T>> createIterator() const = 0;
virtual void addElement(const T& elem) = 0;
virtual int getSize() const = 0;
virtual T getElement(int index) const = 0;
};
// 具体容器:书架
class BookShelf : public Aggregate<Book>
{
private:
std::vector<Book> bookList;
public:
void addElement(const Book& elem) override
{
bookList.push_back(elem);
}
int getSize() const override
{
return bookList.size();
}
Book getElement(int index) const override
{
return bookList[index];
}
std::unique_ptr<Iterator<Book>> createIterator() const override;
};
// 具体迭代器:书架迭代器
class BookShelfIterator : public Iterator<Book>
{
private:
const BookShelf* shelf;
int currentIndex;
public:
BookShelfIterator(const BookShelf* shelfObj)
: shelf(shelfObj), currentIndex(0) {}
bool hasNext() const override
{
return currentIndex < shelf->getSize();
}
Book next() override
{
return shelf->getElement(currentIndex++);
}
};
// 容器绑定迭代器
std::unique_ptr<Iterator<Book>> BookShelf::createIterator() const
{
return std::make_unique<BookShelfIterator>(this);
}
// 客户端调用
int main()
{
BookShelf shelf;
shelf.addElement(Book("C++设计模式"));
shelf.addElement(Book("数据结构与算法"));
shelf.addElement(Book("Linux编程实战"));
auto iterator = shelf.createIterator();
std::cout << "书架内书籍列表:\n";
while (iterator->hasNext())
{
Book book = iterator->next();
std::cout << book.getName() << std::endl;
}
return 0;
}
五、通用模板示例:自定义任务容器遍历
cpp
#include <iostream>
#include <vector>
#include <memory>
// 通用抽象迭代器
template<typename T>
class BaseIterator
{
public:
virtual ~BaseIterator() = default;
virtual bool existNext() = 0;
virtual T fetchNext() = 0;
};
// 通用抽象容器
template<typename T>
class BaseContainer
{
public:
virtual ~BaseContainer() = default;
virtual std::unique_ptr<BaseIterator<T>> getIterator() = 0;
virtual void append(const T& data) = 0;
virtual size_t getLength() const = 0;
virtual T getData(size_t idx) const = 0;
};
// 线性存储容器
template<typename T>
class LinearContainer : public BaseContainer<T>
{
private:
std::vector<T> dataArr;
public:
void append(const T& data) override
{
dataArr.push_back(data);
}
size_t getLength() const override
{
return dataArr.size();
}
T getData(size_t idx) const override
{
return dataArr[idx];
}
std::unique_ptr<BaseIterator<T>> getIterator() override;
};
// 线性容器迭代器
template<typename T>
class LinearIterator : public BaseIterator<T>
{
private:
LinearContainer<T>* container;
size_t cursor;
public:
LinearIterator(LinearContainer<T>* con) : container(con), cursor(0) {}
bool existNext() override
{
return cursor < container->getLength();
}
T fetchNext() override
{
return container->getData(cursor++);
}
};
template<typename T>
std::unique_ptr<BaseIterator<T>> LinearContainer<T>::getIterator()
{
return std::make_unique<LinearIterator<T>>(this);
}
// 测试使用
int main()
{
LinearContainer<std::string> taskContainer;
taskContainer.append("路径规划");
taskContainer.append("环境检测");
taskContainer.append("设备自检");
auto iter = taskContainer.getIterator();
std::cout << "\n机器人任务清单:\n";
while (iter->existNext())
{
std::cout << iter->fetchNext() << std::endl;
}
return 0;
}
六、迭代器分类说明
- 外部迭代器
客户端主动控制遍历启停、游标移动,日常开发最常用。 - 内部迭代器
迭代器自身完成全部遍历逻辑,客户端仅发起遍历请求。 - 正向迭代器
仅支持从头部向尾部单向遍历。 - 双向迭代器
可前后移动游标,支持正反遍历元素。 - 随机访问迭代器
支持下标取值、游标跳跃访问,访问效率最高。
七、与C++ STL迭代器关联
STL容器遍历是迭代器模式工业化落地实现
begin()、end()等同于创建迭代器对象++、--运算符实现游标移动*解引用运算符获取容器元素- 统一遍历接口,vector、list、map可复用遍历代码
cpp
#include <iostream>
#include <vector>
int main()
{
std::vector<int> numVec = {10,20,30,40};
// STL标准迭代器用法
for (auto it = numVec.begin(); it != numVec.end(); ++it)
{
std::cout << *it << " ";
}
return 0;
}
八、模式优缺点
8.1 优点
- 统一遍历接口,适配多种异构容器,遍历代码可复用
- 屏蔽容器底层存储细节,提升数据安全性
- 存储与遍历职责拆分,代码结构清晰易维护
- 可同时创建多个迭代器,并行遍历同一容器
- 灵活扩展遍历方式,正序、倒序、过滤遍历互不影响
8.2 缺点
- 每新增一种容器,需配套编写对应迭代器类,类数量增加
- 极简小型集合使用该模式,存在代码冗余、过度设计
- 遍历过程中修改容器结构,容易引发迭代器失效问题
九、适用业务场景
- 项目存在多种不同存储结构的集合,需要统一遍历方式
- 要求隐藏容器内部数据组织,禁止外部直接访问底层结构
- 同一集合需要提供多种遍历规则、访问顺序
- 分离数据存储与遍历逻辑,降低模块间耦合
- 任务队列、数据集、地图节点、日志条目遍历场景
十、相近模式区分
| 模式 | 核心作用 | 侧重点 |
|---|---|---|
| 迭代器模式 | 统一访问集合元素 | 容器遍历、隐藏内部结构 |
| 组合模式 | 统一处理树形整体与节点 | 层级递归遍历对象 |
| 访问者模式 | 在不修改类前提下新增操作 | 对元素执行自定义业务操作 |
十一、C++工程编码规范
- 使用
std::unique_ptr管理迭代器实例,自动回收内存 - 迭代器仅做元素访问,不修改容器内部数据与结构
- 遍历周期内避免增删元素,防止迭代器失效崩溃
- 常规业务优先使用STL原生迭代器,自定义特殊容器再手写迭代器
- 抽象接口精简通用,保证不同迭代器调用规则一致
十二、模式总结
迭代器模式核心是访问分离、结构隐藏、接口统一 。
通过独立迭代器接管遍历逻辑,让容器专注数据存储,客户端以通用方式读取元素,无需感知底层实现。该模式是C++容器体系的基础设计思想,广泛应用于数据遍历、任务处理、集合管理等业务场景,有效简化多容器兼容开发成本。