迭代器模式(Iterator)是行为型设计模式的一种,它提供了一种顺序访问聚合对象元素的方法,而无需暴露聚合对象的内部结构。这种模式将遍历逻辑与聚合对象分离,使遍历操作更加灵活,同时支持对同一聚合对象进行多种不同的遍历。
一、核心思想与角色
迭代器模式的核心是"分离聚合与遍历",通过引入迭代器对象统一遍历接口,使客户端可以用相同的方式遍历不同的聚合结构。其核心角色如下:
角色名称 | 核心职责 |
---|---|
抽象迭代器(Iterator) | 定义遍历聚合对象的接口,包含hasNext() (是否有下一个元素)和next() (获取下一个元素)等方法。 |
具体迭代器(ConcreteIterator) | 实现抽象迭代器接口,记录当前遍历位置,完成实际的遍历逻辑。 |
抽象聚合(Aggregate) | 定义创建迭代器的接口(如createIterator() ),声明聚合对象的基本操作。 |
具体聚合(ConcreteAggregate) | 实现抽象聚合接口,存储元素集合,返回具体迭代器实例。 |
客户端(Client) | 通过抽象迭代器接口遍历聚合对象,无需关心聚合的具体类型和内部结构。 |
核心思想:将聚合对象的遍历逻辑封装到迭代器中,客户端通过迭代器接口访问聚合元素,使聚合与遍历解耦,同时支持多种遍历方式(如正序、逆序)。
二、实现示例(自定义集合与迭代器)
假设我们需要实现一个自定义的动态数组(DynamicArray
)和链表(LinkedList
),并为它们提供统一的遍历接口。使用迭代器模式可使客户端用相同的方式遍历两种不同的聚合结构:
cpp
#include <iostream>
#include <string>
// 1. 抽象迭代器
template <typename T>
class Iterator {
public:
virtual bool hasNext() const = 0; // 是否有下一个元素
virtual T next() = 0; // 获取下一个元素
virtual ~Iterator() = default;
};
// 2. 抽象聚合
template <typename T>
class Aggregate {
public:
virtual Iterator<T>* createIterator() = 0; // 创建迭代器
virtual void add(const T& item) = 0; // 添加元素
virtual int size() const = 0; // 获取元素数量
virtual ~Aggregate() = default;
};
// 3. 具体聚合1:动态数组
template <typename T>
class DynamicArray : public Aggregate<T> {
private:
T* elements; // 元素数组
int capacity; // 容量
int count; // 当前元素数量
// 扩容
void resize() {
capacity *= 2;
T* newElements = new T[capacity];
for (int i = 0; i < count; ++i) {
newElements[i] = elements[i];
}
delete[] elements;
elements = newElements;
}
public:
DynamicArray(int initialCapacity = 4)
: capacity(initialCapacity), count(0) {
elements = new T[capacity];
}
// 添加元素
void add(const T& item) override {
if (count >= capacity) {
resize();
}
elements[count++] = item;
}
// 获取指定位置元素(供迭代器使用)
T get(int index) const {
if (index >= 0 && index < count) {
return elements[index];
}
throw std::out_of_range("索引越界");
}
int size() const override {
return count;
}
// 创建数组迭代器
Iterator<T>* createIterator() override;
~DynamicArray() {
delete[] elements;
}
};
// 3. 具体迭代器1:数组迭代器
template <typename T>
class ArrayIterator : public Iterator<T> {
private:
DynamicArray<T>* array; // 关联的数组
int currentIndex; // 当前索引
public:
ArrayIterator(DynamicArray<T>* arr) : array(arr), currentIndex(0) {}
bool hasNext() const override {
return currentIndex < array->size();
}
T next() override {
if (hasNext()) {
return array->get(currentIndex++);
}
throw std::out_of_range("没有更多元素");
}
};
// 为DynamicArray实现createIterator(需在ArrayIterator定义后)
template <typename T>
Iterator<T>* DynamicArray<T>::createIterator() {
return new ArrayIterator<T>(this);
}
// 3. 具体聚合2:链表
template <typename T>
class LinkedList : public Aggregate<T> {
private:
// 链表节点
struct Node {
T data;
Node* next;
Node(const T& d) : data(d), next(nullptr) {}
};
Node* head; // 头节点
int count; // 元素数量
public:
LinkedList() : head(nullptr), count(0) {}
void add(const T& item) override {
Node* newNode = new Node(item);
if (!head) {
head = newNode;
} else {
Node* current = head;
while (current->next) {
current = current->next;
}
current->next = newNode;
}
count++;
}
int size() const override {
return count;
}
// 获取头节点(供迭代器使用)
Node* getHead() const {
return head;
}
// 创建链表迭代器
Iterator<T>* createIterator() override;
~LinkedList() {
Node* current = head;
while (current) {
Node* next = current->next;
delete current;
current = next;
}
}
};
// 3. 具体迭代器2:链表迭代器
template <typename T>
class ListIterator : public Iterator<T> {
private:
typename LinkedList<T>::Node* current; // 当前节点(注意typename声明嵌套类型)
public:
ListIterator(LinkedList<T>* list) : current(list->getHead()) {}
bool hasNext() const override {
return current != nullptr;
}
T next() override {
if (hasNext()) {
T data = current->data;
current = current->next;
return data;
}
throw std::out_of_range("没有更多元素");
}
};
// 为LinkedList实现createIterator
template <typename T>
Iterator<T>* LinkedList<T>::createIterator() {
return new ListIterator<T>(this);
}
// 客户端代码:统一遍历不同聚合
template <typename T>
void printAggregate(Aggregate<T>* aggregate) {
Iterator<T>* iterator = aggregate->createIterator();
std::cout << "元素列表:";
while (iterator->hasNext()) {
std::cout << iterator->next() << " ";
}
std::cout << std::endl;
delete iterator;
}
int main() {
// 测试动态数组
Aggregate<int>* array = new DynamicArray<int>();
array->add(10);
array->add(20);
array->add(30);
std::cout << "遍历动态数组:" << std::endl;
printAggregate(array);
// 测试链表
Aggregate<std::string>* list = new LinkedList<std::string>();
list->add("Hello");
list->add("World");
list->add("Iterator");
std::cout << "\n遍历链表:" << std::endl;
printAggregate(list);
// 释放资源
delete array;
delete list;
return 0;
}
三、代码解析
-
抽象迭代器(Iterator) :
定义了模板接口,包含
hasNext()
(判断是否有下一个元素)和next()
(获取下一个元素)方法,为所有具体迭代器提供统一规范。 -
抽象聚合(Aggregate) :
定义了模板接口,包含
createIterator()
(创建迭代器)、add()
(添加元素)和size()
(获取大小)方法,所有聚合类都需实现这些接口。 -
具体聚合与迭代器:
- 动态数组(DynamicArray) :内部用数组存储元素,实现了
add()
等方法,createIterator()
返回ArrayIterator
实例。 - 数组迭代器(ArrayIterator) :记录当前索引(
currentIndex
),通过hasNext()
判断是否越界,next()
返回当前元素并递增索引。 - 链表(LinkedList) :内部用节点链表存储元素,
createIterator()
返回ListIterator
实例。 - 链表迭代器(ListIterator) :记录当前节点(
current
),hasNext()
判断节点是否为空,next()
返回当前节点数据并移动到下一个节点。
- 动态数组(DynamicArray) :内部用数组存储元素,实现了
-
客户端使用 :
客户端通过
printAggregate()
函数统一遍历不同聚合(数组和链表),该函数仅依赖抽象的Aggregate
和Iterator
接口,无需知道具体聚合类型,体现了"依赖倒置原则"。
四、核心优势与适用场景
优势
- 解耦聚合与遍历:聚合对象无需关心遍历逻辑,迭代器专注于遍历,符合单一职责原则。
- 统一遍历接口:客户端可用相同的代码遍历不同的聚合结构(如数组、链表、树),简化了客户端代码。
- 支持多种遍历:可为同一聚合提供多种迭代器(如正序、逆序、过滤迭代器),客户端按需选择。
- 隐藏内部结构:迭代器屏蔽了聚合对象的内部实现(如数组的索引、链表的节点),保护了聚合的封装性。
适用场景
- 需要遍历复杂聚合结构:如自定义集合类(数组、链表、哈希表)、树形结构(二叉树、目录树)。
- 希望统一遍历接口 :当系统中有多种聚合类型,且希望客户端用一致的方式遍历时(如STL中的
begin()
/end()
)。 - 需要多种遍历方式:如对集合同时支持正序遍历、逆序遍历、按条件过滤遍历。
五、与其他模式的区别
模式 | 核心差异点 |
---|---|
迭代器模式 | 专注于聚合对象的遍历,分离遍历逻辑与聚合结构,提供统一遍历接口。 |
访问者模式 | 通过访问者对象为不同元素添加新操作,不关注遍历,侧重操作扩展。 |
组合模式 | 构建树形结构表示"部分-整体"关系,可与迭代器模式结合使用(如遍历组合对象)。 |
工厂模式 | 迭代器的创建过程可通过工厂模式实现(如createIterator() 本质是工厂方法)。 |
六、实践建议
- 使用模板实现通用迭代器:如示例中使用C++模板,使迭代器可支持任意数据类型,提高复用性。
- 实现双向迭代器 :对于需要反向遍历的场景,可扩展迭代器接口,添加
hasPrevious()
和previous()
方法。 - 支持迭代器失效处理:当聚合对象被修改(如添加/删除元素)时,需考虑迭代器是否失效(如STL中的迭代器失效规则)。
- 结合C++11迭代器特性 :在实际开发中,可遵循C++标准库的迭代器设计(如
begin()
/end()
、++
运算符重载),提高代码兼容性。
迭代器模式的核心价值在于"标准化遍历操作,隔离聚合与遍历"。它通过统一的迭代器接口,使客户端可以忽略聚合对象的内部结构,用一致的方式遍历各种集合,同时为扩展新的聚合类型或遍历方式提供了便利。在设计自定义集合类或需要统一遍历逻辑的场景中,迭代器模式是不可或缺的设计选择。