C++设计模式-迭代器模式:从基本介绍,内部原理、应用场景、使用方法,常见问题和解决方案进行深度解析

一、基本介绍

迭代器模式(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);
    }
};

六、总结

模式优势分析

  1. 解耦遍历逻辑:将迭代算法与数据结构分离;
  2. 多态遍历支持:支持正向、反向、过滤等多种迭代方式;
  3. 接口统一性:标准化访问方式降低系统耦合度;

适用性建议

  • 需要支持多种遍历方式的复杂数据结构 ;
  • 需隐藏容器内部实现细节的场景 ;
  • 跨平台数据访问层设计 ;

发展趋势

结合现代C++特性进行增强:

  1. 使用RAII管理迭代器生命周期 。
cpp 复制代码
auto iter = std::make_unique<CustomIterator>(list);
  1. 利用C++20概念约束迭代器类型。
cpp 复制代码
template<typename T>
concept Iterable = requires(T t) {
    { t.begin()  } -> std::input_iterator;
    { t.end()  } -> std::sentinel_for<decltype(t.begin())>; 
};
  1. 协程实现异步迭代器。
    迭代器模式在STL中的成功应用(如vector::iterator)证明了其重要价值。

随着C++标准的发展,该模式将继续在异步编程、并行计算等领域发挥关键作用。我们根据具体场景灵活运用,在保证扩展性的同时注意性能优化。

相关推荐
序属秋秋秋7 分钟前
算法基础_基础算法【高精度 + 前缀和 + 差分 + 双指针】
c语言·c++·学习·算法
肥仔哥哥193037 分钟前
设计模式分类与定义(高软55)
设计模式·软考·高软·设计模式分类
KeithTsui1 小时前
GCC RISCV 后端 -- 控制流(Control Flow)的一些理解
linux·c语言·开发语言·c++·算法
mNinGInG1 小时前
c++练习
开发语言·c++·算法
EPSDA1 小时前
Boost库中的谓词函数
c++
yuanbenshidiaos2 小时前
面试问题总结:qt工程师/c++工程师
c++·qt·面试
半盏茶香3 小时前
启幕数据结构算法雅航新章,穿梭C++梦幻领域的探索之旅——堆的应用之堆排、Top-K问题
java·开发语言·数据结构·c++·python·算法·链表
小竹子143 小时前
L1-1 天梯赛座位分配
数据结构·c++·算法
v维焓4 小时前
C++(思维导图更新)
开发语言·c++·算法
云徒川4 小时前
【设计模式】过滤器模式
windows·python·设计模式