什么是迭代器模式?
迭代器模式是一种行为型设计模式,它允许我们顺序地访问一个集合中的元素,而无需了解集合的内部结构。
通俗解释
- 迭代器模式就像一本书的书签,可以逐页翻阅内容,而不需要关心书的具体装订方式。
- 比如:我们在遍历数组、链表或集合时,只需要迭代器提供的接口来访问数据,而无需知道数组或链表的实现细节。
迭代器模式的特点
-
解耦遍历逻辑和集合实现:
- 迭代器提供统一的接口,用户无需关心集合的内部结构(比如数组、链表等)。
-
提供多种遍历方式:
- 可以实现正序遍历、逆序遍历等不同方式。
-
统一集合的访问方式:
- 通过迭代器,可以用相同的方式访问不同类型的集合。
迭代器模式的结构
UML 类图
+--------------------+
| Iterator | // 抽象迭代器接口
+--------------------+
| + first() |
| + next() |
| + isDone() |
| + currentItem() |
+--------------------+
^
|
+---------------------------+
| ConcreteIterator | // 具体迭代器
+---------------------------+
^
|
+--------------------+
| Aggregate | // 抽象集合
+--------------------+
| + createIterator()|
+--------------------+
^
|
+---------------------------+
| ConcreteAggregate | // 具体集合
+---------------------------+
组成部分
-
Iterator
(抽象迭代器)- 定义了访问集合元素的接口,例如
first()
、next()
、isDone()
、currentItem()
。
- 定义了访问集合元素的接口,例如
-
ConcreteIterator
(具体迭代器)- 实现
Iterator
接口,负责遍历具体集合的元素。
- 实现
-
Aggregate
(抽象集合)- 定义集合的接口,通常包含创建迭代器的方法
createIterator()
。
- 定义集合的接口,通常包含创建迭代器的方法
-
ConcreteAggregate
(具体集合)- 实现
Aggregate
接口,存储数据,并提供方法创建迭代器。
- 实现
迭代器模式的优点和缺点
优点
- 封装集合内部结构:使用迭代器可以隐藏集合的实现细节。
- 统一遍历接口:不同类型的集合可以通过相同的迭代器接口进行访问。
- 扩展性强:可以轻松增加新的迭代器类型(如逆序迭代器)。
缺点
- 类的数量增加:每种集合都需要一个具体的迭代器类。
- 额外的开销:迭代器的创建和维护会带来额外的性能开销。
案例:图书馆书籍集合遍历
需求描述
- 我们需要设计一个图书馆的书籍管理系统,其中图书馆存储了一些书籍。
- 用户可以通过迭代器来逐本访问这些书籍,而无需关心书籍存储的方式(例如是数组还是链表)。
代码实现
以下是完整的代码实现,输出信息为中文,并配有详细注释。
#include <iostream>
#include <vector>
#include <string>
#include <memory>
// 抽象迭代器接口
class Iterator {
public:
virtual void first() = 0; // 将迭代器移动到第一个元素
virtual void next() = 0; // 移动到下一个元素
virtual bool isDone() const = 0; // 检查是否已到达集合末尾
virtual std::string currentItem() const = 0; // 获取当前元素
virtual ~Iterator() = default;
};
// 抽象集合接口
class Aggregate {
public:
virtual std::shared_ptr<Iterator> createIterator() = 0; // 创建迭代器
virtual ~Aggregate() = default;
};
// 具体集合类:书籍集合
class BookCollection : public Aggregate {
private:
std::vector<std::string> books; // 用于存储书籍的集合
public:
// 添加书籍
void addBook(const std::string& book) {
books.push_back(book);
}
// 获取书籍总数
size_t getSize() const {
return books.size();
}
// 根据索引获取书籍
std::string getBook(size_t index) const {
if (index < books.size()) {
return books[index];
}
return "";
}
// 实现创建迭代器的方法
std::shared_ptr<Iterator> createIterator() override;
// 声明迭代器为友元类,方便访问私有数据
friend class BookIterator;
};
// 具体迭代器类:书籍迭代器
class BookIterator : public Iterator {
private:
const BookCollection& collection; // 引用书籍集合
size_t currentIndex; // 当前迭代器位置
public:
// 构造函数
BookIterator(const BookCollection& collection)
: collection(collection), currentIndex(0) {}
// 实现迭代器接口方法
void first() override {
currentIndex = 0; // 移动到第一个元素
}
void next() override {
if (currentIndex < collection.getSize()) {
++currentIndex; // 移动到下一个元素
}
}
bool isDone() const override {
return currentIndex >= collection.getSize(); // 检查是否到达集合末尾
}
std::string currentItem() const override {
if (!isDone()) {
return collection.getBook(currentIndex); // 返回当前书籍
}
return "无效的书籍"; // 如果越界,返回无效
}
};
// 在BookCollection中实现创建迭代器的方法
std::shared_ptr<Iterator> BookCollection::createIterator() {
return std::make_shared<BookIterator>(*this);
}
// 客户端代码
int main() {
// 创建一个书籍集合
BookCollection library;
library.addBook("C++编程入门");
library.addBook("设计模式详解");
library.addBook("数据结构与算法");
library.addBook("操作系统原理");
// 创建迭代器
auto iterator = library.createIterator();
// 使用迭代器访问集合中的元素
std::cout << "图书馆中的书籍列表:" << std::endl;
for (iterator->first(); !iterator->isDone(); iterator->next()) {
std::cout << " - " << iterator->currentItem() << std::endl;
}
return 0;
}
运行结果
图书馆中的书籍列表:
- C++编程入门
- 设计模式详解
- 数据结构与算法
- 操作系统原理
代码讲解
1. 抽象迭代器接口(Iterator
)
class Iterator {
public:
virtual void first() = 0;
virtual void next() = 0;
virtual bool isDone() const = 0;
virtual std::string currentItem() const = 0;
virtual ~Iterator() = default;
};
first()
:将迭代器移动到集合的第一个元素。next()
:移动到下一个元素。isDone()
:检查是否已经到达集合末尾。currentItem()
:获取当前元素。
2. 抽象集合接口(Aggregate
)
class Aggregate {
public:
virtual std::shared_ptr<Iterator> createIterator() = 0; // 创建迭代器
virtual ~Aggregate() = default;
};
- 定义了一个
createIterator
方法,用于创建迭代器。
3. 具体集合类(BookCollection
)
class BookCollection : public Aggregate {
private:
std::vector<std::string> books;
public:
void addBook(const std::string& book) {
books.push_back(book);
}
size_t getSize() const {
return books.size();
}
std::string getBook(size_t index) const {
if (index < books.size()) {
return books[index];
}
return "";
}
std::shared_ptr<Iterator> createIterator() override {
return std::make_shared<BookIterator>(*this);
}
};
books
存储书籍集合。- 提供了添加书籍、获取书籍的方法。
createIterator
方法返回一个BookIterator
对象。
4. 具体迭代器类(BookIterator
)
class BookIterator : public Iterator {
private:
const BookCollection& collection;
size_t currentIndex;
public:
BookIterator(const BookCollection& collection)
: collection(collection), currentIndex(0) {}
void first() override {
currentIndex = 0;
}
void next() override {
if (currentIndex < collection.getSize()) {
++currentIndex;
}
}
bool isDone() const override {
return currentIndex >= collection.getSize();
}
std::string currentItem() const override {
if (!isDone()) {
return collection.getBook(currentIndex);
}
return "无效的书籍";
}
};
- 通过
currentIndex
记录当前访问位置。 - 实现了迭代器的常用方法,负责逐个访问集合的元素。
模板方法模式的优点和缺点
优点
- 封装集合的访问逻辑:使用迭代器访问集合元素,而无需了解集合的内部结构。
- 统一接口:不同类型的集合可以通过相同的迭代器接口进行遍历。
- 灵活性:可以扩展支持更多类型的集合或迭代方式。
缺点
- 类的数量增加:每种集合都需要一个具体的迭代器类。
- 性能开销:迭代器的实现可能会引入额外的性能开销。
总结
迭代器模式是一个非常实用的设计模式,特别适合需要顺序访问集合元素的场景。在本案例中,我们通过迭代器模式实现了图书馆书籍集合的遍历,展示了如何解耦集合的访问逻辑和实现细节。
适用场景
- 遍历复杂数据结构:如链表、树、图等。
- 提供统一的遍历接口:使得不同集合的遍历方式一致。
迭代器模式的核心思想是分离集合的存储和访问逻辑,在实际开发中非常常见,例如C++标准库中的std::vector
、std::list
的迭代器实现!