让我们通过一个通俗易懂的日常生活例子来解释迭代器模式(Iterator Pattern)。
生活中的实际应用:图书馆中的书架
假设你是一个图书管理员,负责图书馆中的书籍。书架上的书籍按照不同的类别摆放,并且每个书架上有很多书。为了更方便地查看或借阅书籍,我们希望能有一种方法可以按照顺序访问书架上的每一本书,而无需了解书籍如何在书架上排列。
这时,我们可以用迭代器模式来实现这一目标。迭代器模式提供了一种方法,可以顺序访问一个聚合对象中的各个元素,而不需要暴露该对象的内部表示。
主要角色
- 迭代器接口(Iterator):定义访问和遍历元素的接口。
- 具体迭代器(ConcreteIterator):实现迭代器接口,维护遍历的当前位置。
- 聚合对象接口(Aggregate):定义创建迭代器的接口。
- 具体聚合对象(ConcreteAggregate):实现聚合对象接口,返回一个具体迭代器的实例。
编码示例
下面的代码使用迭代器模式来实现图书馆中对书架的遍历。
#include <iostream>
#include <vector>
#include <string>
// 迭代器接口
template <typename T>
class Iterator {
public:
virtual ~Iterator() {}
virtual bool hasNext() = 0;
virtual T next() = 0;
};
// 聚合对象接口
template <typename T>
class Aggregate {
public:
virtual ~Aggregate() {}
virtual Iterator<T>* createIterator() = 0;
};
// 具体迭代器类
class BookShelfIterator : public Iterator<std::string> {
private:
std::vector<std::string>* books;
int index;
public:
BookShelfIterator(std::vector<std::string>* books) : books(books), index(0) {}
bool hasNext() override {
return index < books->size();
}
std::string next() override {
return books->at(index++);
}
};
// 具体聚合对象类
class BookShelf : public Aggregate<std::string> {
private:
std::vector<std::string> books;
public:
void addBook(const std::string& book) {
books.push_back(book);
}
Iterator<std::string>* createIterator() override {
return new BookShelfIterator(&books);
}
};
// 主函数
int main() {
// 创建书架并添加书籍
BookShelf bookShelf;
bookShelf.addBook("C++ 编程");
bookShelf.addBook("设计模式");
bookShelf.addBook("数据结构与算法");
// 创建迭代器
Iterator<std::string>* iterator = bookShelf.createIterator();
// 使用迭代器遍历书籍
while (iterator->hasNext()) {
std::string book = iterator->next();
std::cout << "书籍: " << book << std::endl;
}
// 释放资源
delete iterator;
return 0;
}
代码解释
- 迭代器接口 (
Iterator
):定义了两个主要方法hasNext()
和next()
,用于判断是否还有下一个元素并返回当前元素。 - 具体迭代器 (
BookShelfIterator
):实现迭代器接口,持有一个书籍列表和当前遍历的位置。 - 聚合对象接口 (
Aggregate
):定义了创建迭代器的接口createIterator()
。 - 具体聚合对象 (
BookShelf
):实现聚合对象接口,包含一个书籍列表,可以通过addBook()
方法添加书籍,并通过createIterator()
方法返回一个具体迭代器的实例。
总结
迭代器模式的主要优点是:
- 简化遍历操作:可以轻松遍历一个聚合对象中的元素,而不需要了解其内部结构。
- 解耦合:将遍历操作与集合对象分离,简化了集合对象的设计。
- 一致接口:通过统一的接口遍历不同类型的集合对象。