1.简介
迭代器模式是一种行为设计模式, 让你能在不暴露集合(聚合对象)底层表现形式 (列表、 栈和树等) 的情况下遍历集合(聚合对象)中所有的元素。
迭代器的意义就是将这个行为抽离封装起来,这样客户端只需要调用合适的迭代器,来进行对应的遍历,而不用自己去实现这一行为。
2、结构
迭代器模式主要由以下几个结构组成:
迭代器(Iterator):定义访问和遍历聚合对象中元素的接口,包括获取下一个元素、判断是否还有下一个元素等方法。
具体迭代器(Concrete Iterator):实现迭代器接口,存储聚合对象的当前状态,负责遍历聚合对象中的元素。
聚合对象(Aggregate):定义创建相应迭代器对象的接口,一般是一个集合类,如列表、数组等。
具体聚合对象(Concrete Aggregate):实现聚合对象接口,创建具体迭代器对象,可以通过实现不同的聚合对象来提供不同方式的遍历。
在迭代器模式中,客户端通过获取聚合对象的迭代器,使用迭代器的方法遍历聚合对象中的元素,而无需暴露聚合对象的内部表示。这样可以提高系统的灵活性和可扩展性,同时也降低了聚合对象与迭代器之间的耦合度。
3、实现方式
3.1、案例引入
说到迭代器,大家应该很容易就想到在集合中的迭代器遍历集合的场景,这里我们就通过迭代器模式,自定义简单的集合和迭代器,模拟使用迭代器遍历集合的场景。
3.2、结构分析
在上述场景中,结构分别对应迭代器模式中的角色:
Container:对应迭代器模式中的抽象聚合类
ConcreteContainer:对应迭代器模式中的具体的聚合类
Iterator:对应迭代器模式中的抽象迭代器类;
ConcreteIterator:对应迭代器模式中的具体迭代器类;
3.3、具体实现
只在一个.cpp里实现,实际项目中建议分成多个文件
#pragma once
#include <iostream>
#include <unordered_map>
#include <vector>
#include <list>
#include <string>
using namespace std;
//1. 定义迭代器接口
class Iterator
{
public:
// 下一个
virtual int getNext() = 0;
// 是否有下一个
virtual bool hasMore() = 0;
};
//2. 定义容器接口
class Container
{
public:
virtual Iterator* create_iterator() = 0;
};
//3. 定义具体迭代器
class ConcreteIterator : public Iterator
{
public:
// 构造函数,初始化成员变量
ConcreteIterator(std::vector<int> data) : m_data(data), index(0) {}
// 下一个
virtual int getNext() {
return m_data[index++];
}
// 是否有下一个
virtual bool hasMore() {
return index < m_data.size();
}
private:
std::vector<int> m_data;
int index;
};
// 4.定义具体容器
class ConcreteContainer : public Container
{
public:
// 构造函数
ConcreteContainer(std::vector<int> data) : m_data(data) {}
// 创建迭代器
virtual Iterator* create_iterator() {
return new ConcreteIterator(m_data);
}
private:
std::vector<int> m_data;
};
int main()
{
//1. 创建容器
std::vector<int> data = { 10, 20, 30, 40, 50 };
Container* container = new ConcreteContainer(data);
//2.创建迭代器
Iterator* iterator = container->create_iterator();
//3. 迭代器输出
while (iterator->hasMore()) {
std::cout << iterator->getNext() << " ";
}
// 清除
delete iterator;
delete container;
iterator = nullptr;
container = nullptr;
return 0;
}
3.4 运行结果
4.迭代器模式的优缺点
优点:
- 符合单一职责原则。将遍历行为抽离成单独的类。
- 符合开闭原则。添加新集合或者新迭代器,不改变原有代码
- 代码复用性好。由于迭代器模式将遍历集合的代码封装到迭代器中,因此我们可以将同样的迭代器应用于不同的集合对象,从而减少了重复的代码;
- 可以并行遍历同一集合。 因为每个迭代器对象都包含其自身的遍历状态。
缺点:
- 若对聚合对象只需要进行简单的遍历行为,那使用迭代器模式有些大材小用。
- 系统复杂性提高,类数量较多。
5、应用场景
- 在遍历集合元素时,不希望暴露集合内部的表示方式和数据结构,而是希望通过统一的接口进行操作。 迭代器模式使得我们可以将遍历行为封装在迭代器对象中,并把迭代器对象作为集合类的成员,从而达到这个目的;
- 当需要支持多种遍历方式时,可以使用迭代器模式。例如,在一个列表中,需要实现从前向后和从后向前两种遍历方式,使用迭代器模式非常方便地实现这样的需求;
- 需要提供一种通用的遍历机制,使得不同类型的集合对象都可以被遍历。由于迭代器模式将遍历过程封装在迭代器中,因此我们可以为每一种集合对象都提供一个对应的迭代器;
- 当需要对集合对象进行复杂的遍历操作时,可以使用迭代器模式。例如,有些集合对象可能需要在遍历过程中进行筛选、排序等处理,这些逻辑可以在迭代器中完成,从而使得客户端代码保持简洁。