目录
迭代器模式(Iterator Pattern)是一种【行为型】设计模式,它提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。这种模式将遍历逻辑封装在迭代器对象中,使客户端可以统一使用迭代器来访问不同类型的聚合对象,无需关心对象的具体实现。
一、模式核心概念与结构
迭代器模式包含四个核心角色:
- 迭代器接口(Iterator):定义访问和遍历元素的接口,如
next()
、hasNext()
等方法。 - 具体迭代器(Concrete Iterator):实现迭代器接口,跟踪聚合对象中的当前位置。
- 聚合接口(Aggregate):定义创建迭代器对象的接口,如
createIterator()
方法。 - 具体聚合(Concrete Aggregate):实现聚合接口,创建与之对应的具体迭代器。
二、C++ 实现示例:自定义集合迭代器
以下是一个简单的迭代器模式示例,演示如何为自定义集合实现迭代器:
#include <iostream>
#include <memory>
#include <vector>
// 前向声明
template <typename T> class Iterator;
template <typename T> class ConcreteAggregate;
// 迭代器接口
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::shared_ptr<Iterator<T>> createIterator() = 0;
};
// 具体迭代器
template <typename T>
class ConcreteIterator : public Iterator<T> {
private:
std::shared_ptr<std::vector<T>> collection;
size_t position;
public:
ConcreteIterator(std::shared_ptr<std::vector<T>> coll)
: collection(coll), position(0) {}
bool hasNext() const override {
return position < collection->size();
}
T next() override {
if (hasNext()) {
return (*collection)[position++];
}
throw std::out_of_range("No more elements");
}
};
// 具体聚合
template <typename T>
class ConcreteAggregate : public Aggregate<T> {
private:
std::shared_ptr<std::vector<T>> items;
public:
ConcreteAggregate() : items(std::make_shared<std::vector<T>>()) {}
void addItem(const T& item) {
items->push_back(item);
}
std::shared_ptr<Iterator<T>> createIterator() override {
return std::make_shared<ConcreteIterator<T>>(items);
}
};
// 客户端代码
int main() {
// 创建聚合对象
auto aggregate = std::make_shared<ConcreteAggregate<std::string>>();
aggregate->addItem("Apple");
aggregate->addItem("Banana");
aggregate->addItem("Cherry");
// 创建迭代器
auto iterator = aggregate->createIterator();
// 使用迭代器遍历集合
std::cout << "Items in collection:" << std::endl;
while (iterator->hasNext()) {
std::cout << iterator->next() << std::endl;
}
return 0;
}
三、迭代器模式的关键特性
- 统一遍历接口:
- 客户端通过迭代器接口访问聚合对象,无需关心其内部结构。
- 遍历与聚合分离:
- 迭代器将遍历逻辑从聚合对象中分离出来,使聚合对象可以专注于存储数据。
- 支持多种遍历方式:
- 可以为同一个聚合对象提供不同的迭代器实现,支持不同的遍历策略。
- 简化客户端代码:
- 客户端无需手动管理遍历状态,降低代码复杂度。
四、应用场景
- 访问聚合对象:
- 遍历数组、链表、树等各种数据结构。
- 例如,遍历文件系统目录树、数据库查询结果集。
- 隐藏内部实现:
- 当聚合对象的内部结构复杂或不希望暴露时,使用迭代器封装访问逻辑。
- 支持多种遍历方式:
- 为同一聚合对象提供不同的遍历方式(如正向、反向、深度优先、广度优先)。
- 统一遍历接口:
- 为不同类型的聚合对象提供统一的遍历接口,简化客户端代码。
五、迭代器模式与其他设计模式的关系
- 组合模式:
- 迭代器模式常与组合模式一起使用,用于遍历组合结构中的元素。
- 例如,遍历树形结构中的所有节点。
- 工厂模式:
- 迭代器通常由工厂方法创建,聚合对象通过工厂方法返回具体迭代器。
- 观察者模式:
- 当聚合对象的内容发生变化时,可以使用观察者模式通知所有迭代器。
六、C++ 标准库中的迭代器模式应用
- STL 迭代器:
- C++ 标准模板库(STL)广泛使用迭代器模式,如
std::vector
、std::list
、std::map
等容器都提供迭代器。
- C++ 标准模板库(STL)广泛使用迭代器模式,如
- 范围 for 循环:
- C++11 引入的范围 for 循环依赖于迭代器接口,简化了容器遍历。
- 算法与迭代器分离:
- STL 算法(如
std::find
、std::sort
)通过迭代器操作容器元素,实现了算法与数据结构的解耦。
- STL 算法(如
七、优缺点分析
优点:
- 解耦遍历与聚合:简化聚合类,符合单一职责原则。
- 支持多种遍历方式:可以为同一聚合对象提供不同的迭代器。
- 统一接口:客户端可以一致地处理不同类型的聚合对象。
- 简化客户端代码:无需手动管理遍历状态,降低出错概率。
缺点:
- 类数量增加:每个聚合类都需要对应的迭代器类,可能导致类膨胀。
- 维护成本:当聚合对象的结构发生变化时,可能需要修改迭代器类。
- 功能限制:某些特殊的遍历需求可能需要定制迭代器,增加实现复杂度。
八、实战案例:二叉树迭代器
以下是一个二叉树迭代器的实现示例,支持中序遍历:
#include <iostream>
#include <memory>
#include <stack>
// 前向声明
template <typename T> class BinaryTree;
template <typename T> class BinaryTreeIterator;
// 树节点
template <typename T>
class TreeNode {
public:
T data;
std::shared_ptr<TreeNode<T>> left;
std::shared_ptr<TreeNode<T>> right;
TreeNode(const T& value) : data(value), left(nullptr), right(nullptr) {}
};
// 迭代器接口
template <typename T>
class Iterator {
public:
virtual ~Iterator() = default;
virtual bool hasNext() const = 0;
virtual T next() = 0;
};
// 二叉树迭代器(中序遍历)
template <typename T>
class BinaryTreeIterator : public Iterator<T> {
private:
std::shared_ptr<TreeNode<T>> root;
std::stack<std::shared_ptr<TreeNode<T>>> stack;
std::shared_ptr<TreeNode<T>> current;
public:
BinaryTreeIterator(std::shared_ptr<TreeNode<T>> node) : root(node) {
// 初始化栈,将左子树压入栈
current = root;
while (current) {
stack.push(current);
current = current->left;
}
}
bool hasNext() const override {
return !stack.empty();
}
T next() override {
if (!hasNext()) {
throw std::out_of_range("No more elements");
}
// 弹出栈顶元素
auto node = stack.top();
stack.pop();
// 处理右子树
current = node->right;
while (current) {
stack.push(current);
current = current->left;
}
return node->data;
}
};
// 二叉树聚合类
template <typename T>
class BinaryTree {
private:
std::shared_ptr<TreeNode<T>> root;
public:
BinaryTree() : root(nullptr) {}
void insert(const T& value) {
root = insertRecursive(root, value);
}
std::shared_ptr<TreeNode<T>> insertRecursive(std::shared_ptr<TreeNode<T>> node, const T& value) {
if (!node) {
return std::make_shared<TreeNode<T>>(value);
}
if (value < node->data) {
node->left = insertRecursive(node->left, value);
} else if (value > node->data) {
node->right = insertRecursive(node->right, value);
}
return node;
}
std::shared_ptr<Iterator<T>> createIterator() {
return std::make_shared<BinaryTreeIterator<T>>(root);
}
};
// 客户端代码
int main() {
// 创建二叉树
BinaryTree<int> tree;
tree.insert(5);
tree.insert(3);
tree.insert(7);
tree.insert(2);
tree.insert(4);
tree.insert(6);
tree.insert(8);
// 创建迭代器
auto iterator = tree.createIterator();
// 中序遍历输出
std::cout << "In-order traversal:" << std::endl;
while (iterator->hasNext()) {
std::cout << iterator->next() << " ";
}
std::cout << std::endl;
return 0;
}
九、实现注意事项
- 迭代器失效:
- 当聚合对象的结构发生变化(如插入、删除元素)时,可能导致迭代器失效。
- 需谨慎处理迭代器与聚合对象的同步问题。
- 并发访问:
- 在多线程环境中,需考虑迭代器的线程安全问题,可能需要同步机制。
- 迭代器类型:
- 可以为聚合对象提供多种迭代器(如前序、中序、后序遍历的二叉树迭代器)。
- 简化实现:
- 对于简单的聚合类,可以使用内部类实现迭代器,减少类的数量。
迭代器模式是 C++ 中处理集合遍历的重要工具,通过将遍历逻辑封装在迭代器中,使客户端可以统一、透明地访问不同类型的聚合对象,提高了代码的可维护性和复用性。