一、基本介绍
迭代器模式(Iterator Pattern)是行为型设计模式,其核心在于为聚合对象提供统一的遍历接口,使客户端无需了解底层数据结构即可访问聚合元素。该模式如同图书馆的图书检索系统------读者通过标准化的查询界面查找书籍,无需了解书籍在仓库中的具体存储方式。
模式三要素
- 抽象迭代器(Iterator):定义遍历接口(如next、hasNext);
- 具体迭代器(ConcreteIterator):实现特定遍历逻辑(如链表迭代器);
- 聚合对象(Aggregate):存储元素集合的容器(如自定义链表);
与普通遍历的区别
维度 | 迭代器模式 | 直接遍历 |
---|---|---|
耦合度 | 客户端与容器解耦 | 强依赖容器实现 |
扩展性 | 支持多种遍历策略 | 遍历逻辑固定 |
复用性 | 同一接口遍历不同容器 | 每种容器需单独实现 |
复杂度 | 增加迭代器类 | 简单场景更直接 |
二、内部原理剖析
1. 多态遍历机制
通过抽象迭代器接口实现运行时多态,客户端通过统一接口访问不同容器:
cpp
template<typename T>
class Iterator {
public:
virtual ~Iterator() = default;
virtual bool hasNext() const = 0;
virtual T next() = 0;
};
具体迭代器继承该接口并实现容器特定的遍历逻辑,如链表迭代器维护当前节点指针。
2. 遍历状态封装
迭代器内部保存遍历进度状态,避免外部直接操作容器内部结构:
cpp
class LinkedListIterator : public Iterator<int> {
private:
Node* current;
public:
explicit LinkedListIterator(Node* head) : current(head) {}
bool hasNext() const override {
return current != nullptr;
}
int next() override {
int val = current->data;
current = current->next;
return val;
}
};
3. 双向迭代支持
通过定义反向迭代器实现逆向遍历,提升模式灵活性:
cpp
class ReverseIterator : public Iterator<int> {
private:
Node* current;
public:
explicit ReverseIterator(Node* tail) : current(tail) {}
bool hasNext() const override {
return current != nullptr;
}
int next() override {
int val = current->data;
current = current->prev; // 反向移动指针
return val;
}
};
三、应用场景详解
1. 复杂数据结构遍历
以树形结构的深度优先遍历(DFS)举例,其实现示例如下:
cpp
class TreeIterator : public Iterator<TreeNode*> {
private:
std::stack<TreeNode*> stack;
public:
explicit TreeIterator(TreeNode* root) {
if(root) stack.push(root);
}
bool hasNext() const override {
return !stack.empty();
}
TreeNode* next() override {
TreeNode* node = stack.top();
stack.pop();
if(node->right) stack.push(node->right);
if(node->left) stack.push(node->left);
return node;
}
};
2. 数据库查询结果集
将数据库游标封装为迭代器模式的接口:
cpp
class QueryResultIterator : public Iterator<Row> {
private:
SQLiteStatement* stmt;
public:
explicit QueryResultIterator(SQLiteStatement* statement)
: stmt(statement) {}
bool hasNext() const override {
return stmt->hasNextRow();
}
Row next() override {
return stmt->fetchRow();
}
};
3. 游戏物品系统
比如遍历背包中的武器,并计算总伤害:
cpp
float totalDamage = 0;
auto iter = backpack.createIterator();
while(iter->hasNext()) {
if(auto weapon = dynamic_cast<Weapon*>(iter->next())) {
totalDamage += weapon->getDamage();
}
}
四、使用方法指南
步骤1:定义聚合对象
实现具有迭代器创建接口的容器:
cpp
template<typename T>
class CustomList {
private:
struct Node { T data; Node* next; };
Node* head;
public:
class IteratorImpl : public Iterator<T> {
// 实现迭代器逻辑...
};
Iterator<T>* createIterator() {
return new IteratorImpl(head);
}
};
步骤2:实现具体迭代器
为不同遍历需求创建迭代器子类:
cpp
// 过滤迭代器:仅返回偶数
class EvenNumberIterator : public Iterator<int> {
private:
Iterator<int>* source;
public:
explicit EvenNumberIterator(Iterator<int>* src) : source(src) {}
bool hasNext() const override {
while(source->hasNext()) {
if(source->peekNext() % 2 == 0)
return true;
source->next();
}
return false;
}
int next() override {
return source->next();
}
};
步骤3:客户端调用
cpp
//统一接口访问不同容器
void printAll(Iterator<std::string>* iter) {
while(iter->hasNext()) {
std::cout << iter->next() << std::endl;
}
}
// 使用示例
CustomList<std::string> list;
auto iter = list.createIterator();
printAll(iter);
五、常见问题与解决方案
问题1:迭代器失效
场景 :容器在遍历期间被修改。
解决方案:
- 采用版本号机制检测修改;
- 使用快照迭代器(复制容器数据);
cpp
class SnapshotIterator : public Iterator<T> {
private:
std::vector<T> snapshot;
size_t index = 0;
public:
explicit SnapshotIterator(const CustomList<T>& list) {
auto iter = list.createIterator();
while(iter->hasNext()) {
snapshot.push_back(iter->next());
}
}
// 实现hasNext/next...
};
问题2:多线程竞争
场景 :并发遍历导致数据不一致。
解决方案:
- 为迭代器加互斥锁;
- 使用线程局部存储(TLS);
cpp
class ThreadSafeIterator : public Iterator<T> {
private:
Iterator<T>* source;
std::mutex mtx;
public:
bool hasNext() const override {
std::lock_guard<std::mutex> lock(mtx);
return source->hasNext();
}
T next() override {
std::lock_guard<std::mutex> lock(mtx);
return source->next();
}
};
问题3:性能优化
场景:大规模数据遍历效率低下。
优化策略:
预计算遍历路径(适用于树结构);
内存连续性优化(使用内存池);
cpp
// 内存池分配节点
template<typename T>
class MemoryPoolList {
private:
std::vector<Node*> chunks;
Node* freeList;
public:
Iterator<T>* createIterator() {
return new CacheFriendlyIterator(head);
}
};
六、总结
模式优势分析
- 解耦遍历逻辑:将迭代算法与数据结构分离;
- 多态遍历支持:支持正向、反向、过滤等多种迭代方式;
- 接口统一性:标准化访问方式降低系统耦合度;
适用性建议
- 需要支持多种遍历方式的复杂数据结构 ;
- 需隐藏容器内部实现细节的场景 ;
- 跨平台数据访问层设计 ;
发展趋势
结合现代C++特性进行增强:
- 使用RAII管理迭代器生命周期 。
cpp
auto iter = std::make_unique<CustomIterator>(list);
- 利用C++20概念约束迭代器类型。
cpp
template<typename T>
concept Iterable = requires(T t) {
{ t.begin() } -> std::input_iterator;
{ t.end() } -> std::sentinel_for<decltype(t.begin())>;
};
- 协程实现异步迭代器。
迭代器模式在STL中的成功应用(如vector::iterator)证明了其重要价值。
随着C++标准的发展,该模式将继续在异步编程、并行计算等领域发挥关键作用。我们根据具体场景灵活运用,在保证扩展性的同时注意性能优化。