【声明】本题目来源于卡码网(https://kamacoder.com/)
【提示:如果不想看文字介绍,可以直接跳转到C++编码部分】
--什么是迭代器模式(第19种设计模式)
迭代器模式是⼀种行为设计模式,是⼀种使⽤频率⾮常⾼的设计模式,在各个语⾔中都有应用,其主要⽬的是提供⼀种统⼀的⽅式来访问⼀个聚合对象中的各个元素,而不需要暴露该对象的内部表示。通过迭代器,客户端可以顺序访问聚合对象的元素,而无需了解底层数据结构。
迭代器模式应⽤⼴泛,但是⼤多数语⾔都已经内置了迭代器接⼝,不需要⾃⼰实现。
迭代器模式包括以下⼏个重要角色
下面以Java代码作以说明:
1. 定义迭代器接口:通常会有检查是否还有下⼀个元素以及获取下⼀个元素的⽅法。
// 迭代器接⼝
public interface Iterator{
// 检查是否还会有下⼀个元素
boolean hasNext();
// 获取下⼀个元素
Object next();
}
2. 定义具体迭代器:实现迭代器接口,遍历集合。
public class ConcreteIterator implements Iterator {
private int index;
private List<Object> elements;
// 构造函数初始化迭代器
public ConcreteIterator(List<Object> elements) {
this.elements = elements;
this.index = 0;
}
@Override
public boolean hasNext() {
return index < elements.size();
}
@Override
public Object next() {
if (hasNext()) {
return elements.get(index++);
}
return null;
}
}
3. 定义聚合接口:通常包括createIterator() ⽅法,⽤于创建迭代器
public interface Iterable {
Iterator createIterator();
}
4. 实现具体聚合:创建具体的迭代器
// 具体聚合
public class ConcreteIterable implements Iterable {
private List<Object> elements;
// 构造函数初始化可迭代对象
public ConcreteIterable(List<Object> elements) {
this.elements = elements;
}
@Override
public Iterator createIterator() {
return new ConcreteIterator(elements);
}
}
5. 客户端使用
/**
* @version Copyright (c) 2024 NCDC, Servo。 Unpublished - All rights reserved
* @file TemplateMethodMode.hpp
* @brief 模板方法模式
* @autor 写代码的小恐龙er
* @date 2024/01/23
*/
import java.util.ArrayList;
import java.util.List;
public class IteratorPatternExample {
public static void main(String[] args) {
List<Object> elements = new ArrayList<>();
elements.add("Element 1");
elements.add("Element 2");
elements.add("Element 3");
Iterable iterable = new ConcreteIterable(elements);
Iterator iterator = iterable.createIterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
迭代器模式是⼀种通用的设计模式,其封装性强,简化了客户端代码,客户端不需要知道集合的内部结构,只需要关心迭代器和迭代接口就可以完成元素的访问。但是引⼊迭代器模式会增加额外的类,每增加⼀个集合类,都需要增加该集合对应的迭代器,这也会使得代码结构变得更加复杂。
许多编程语⾔和框架都使用了这个模式提供⼀致的遍历和访问集合元素的机制。下⾯是几种常见语⾔迭代器模式的实现。
集合类(如ArrayList、LinkedList), 通过Iterator 接⼝,可以遍历集合中的元素。
List<String> list = new ArrayList<>();
list.add("Item 1");
list.add("Item 2");
list.add("Item 3");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
使用迭代器和⽣成器来实现迭代模式, iter() 和next() 函数可以⽤于创建和访问迭代器。
elements = ["Element 1", "Element 2", "Element 3"]
iterator = iter(elements)
while True:
try:
element = next(iterator)
print(element)
except StopIteration:
break
C++中的STL提供了迭代器的⽀持, begin() 和end() 函数可以⽤于获取容器的起始和结束迭代器。
#include <iostream>
#include <vector>
int main() {
std::vector<std::string> elements = {"Element 1", "Element 2", "Element 3"};
for (auto it = elements.begin(); it != elements.end(); ++it) {
std::cout << *it << std::endl;
}
return 0;
}
ES6中新增了迭代器协议,使得遍历和访问集合元素变得更加方便。
// 可迭代对象实现可迭代协议
class IterableObject {
constructor() {
this.elements = [];
}
addElement(element) {
this.elements.push(element);
}
[Symbol.iterator]() {
let index = 0;
// 迭代器对象实现迭代器协议
return {
next: () => {
if (index < this.elements.length) {
return { value: this.elements[index++], done: false };
} else {
return { done: true };
}
}
};
}
}
// 使⽤迭代器遍历可迭代对象
const iterableObject = new IterableObject();
iterableObject.addElement("Element 1");
iterableObject.addElement("Element 2");
iterableObject.addElement("Element 3");
for (const element of iterableObject) {
console.log(element);
}
小明是一位老师,在进行班级点名时,希望有一个学生名单系统,请你实现迭代器模式提供一个迭代器使得可以按顺序遍历学生列表。
第一行是一个整数 N (1 <= N <= 100), 表示学生的数量。接下来的 N 行,每行包含一个学生的信息,格式为 姓名 学号;
输出班级点名的结果,即按顺序遍历学生列表,输出学生的姓名和学号;
/**
* @version Copyright (c) 2024 NCDC, Servo。 Unpublished - All rights reserved
* @file IteratorMode.hpp
* @brief 迭代器模式
* @autor 写代码的小恐龙er
* @date 2024/01/23
*/
#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
using namespace std;
// 前置声明
// 聚合元素类 -- 学生
class Student;
// 迭代器接口 -- 提前声明模板
template<class T>
class Iterator;
// 具体迭代器 -- 学生遍历 迭代类
class ConcreteStudentIterator;
// 聚合接口 -- 学生全体类
class StudentCollection;
// 具体的聚合类 -- 创建全体学生
class ConcreteStudentCollection;
// 类的实现
// 聚合元素类 -- 学生
class Student{
// 成员数据
private:
string _name;
int _idNumber;
// 成员函数
public:
// 构造函数
Student(string name, int id){
this->_name = name;
this->_idNumber = id;
}
// 获取成员数据
string GetName(){
return this->_name;
}
int GetIdNumber(){
return this->_idNumber;
}
};
// 迭代器接口
// 类模板
template<class T>
class Iterator{
// 迭代器接口
public:
// 接口函数声明为 纯虚函数
virtual bool isHavNext() = 0;
virtual T* Next() = 0;
};
// 具体迭代器 -- 学生遍历 迭代类
class ConcreteStudentIterator : public Iterator<Student>
{
// 成员数据
private:
std::vector<Student *> _studentsVec;
int _currentIndex = 0;
// 成员函数
public:
// 构造函数
ConcreteStudentIterator(std::vector<Student *> studentsVec){
this->_studentsVec = studentsVec;
}
// 重载接口函数
bool isHavNext() override{
return _currentIndex < _studentsVec.size();
}
Student* Next() override {
if(isHavNext()){
return _studentsVec[_currentIndex++];
}
return nullptr;
}
};
// 聚合接口 -- 学生全体类
class StudentCollection
{
// 迭代器对象 接口函数
public:
virtual Iterator<Student> * iterator() = 0;
};
// 具体的聚合类 -- 创建全体学生
class ConcreteStudentCollection : public StudentCollection
{
// 成员数据
private:
std::vector<Student *> _students;
// 成员函数
public:
// 构造函数
ConcreteStudentCollection(){}
ConcreteStudentCollection(std::vector<Student *> students){
this->_students = students;
}
// 添加学生对象
void AddStudent(Student * student){
_students.push_back(student);
}
// 迭代器接口函数重载 返回值为迭代器基类的指针 模板类型为Student
Iterator<Student> * iterator() override{
// 涉及到 隐式地 向上类型转换 派生类 转换为 基类 线程安全
return new ConcreteStudentIterator(_students);
}
};
int main()
{
// 学生数量
int studentNum = 0;
// 输入
std::cin >> studentNum;
// 创建学生类
Student *student = nullptr;
// 创建具体可迭代对象
ConcreteStudentCollection *concreteStudentCollection = new ConcreteStudentCollection();
// 学生遍历
for(int i = 0; i < studentNum; i++){
// 学生姓名和学号
string name = "";
int numberId = 0;
// 输入
std::cin >> name >> numberId;
// 构造学生类
student = new Student(name, numberId);
// 将学生放入 学生收集器类 中
concreteStudentCollection->AddStudent(student);
}
// 遍历结束后 再来通过迭代器模式 进行 信息打印
// 调用具体聚合类中的 迭代器生成 接口!
Iterator<Student> *iterator = concreteStudentCollection->iterator();
while(iterator->isHavNext()){
// 从迭代器中的学生集合获取学生类
student = iterator->Next();
// 打印学生信息
if(student != nullptr){
// 由于学生类中的成员数据为私有类型 记得调用接口函数去获取成员数据
// 输出长度不足补0; 固定输出长度为3;
std::cout << student->GetName() << " " << setw(3) << setfill('0') << student->GetIdNumber() << endl;
}
else std::cout << "Invalid input" << endl;
}
// 记得析构!!!
// 记得析构!!!
// 记得析构!!!
if(student != nullptr){
delete student;
student = nullptr;
}
delete concreteStudentCollection;
concreteStudentCollection = nullptr;
return 0;
}
......
To be continued.
更多【迭代器模式-C++设计模式之迭代器模式】相关视频教程:www.yxfzedu.com