C++设计模式之迭代器模式

【声明】本题目来源于卡码网(https://kamacoder.com/
【提示:如果不想看文字介绍,可以直接跳转到C++编码部分


设计模式大纲】

【简介】

--什么是迭代器模式(第19种设计模式)

迭代器模式 是⼀种行为设计模式 ,是⼀种使⽤频率⾮常⾼的设计模式,在各个语⾔中都有应用,其主要⽬的是提供⼀种统⼀的⽅式来访问⼀个聚合对象中的各个元素 ,而不需要暴露该对象的内部表示 。通过迭代器,客户端可以顺序访问聚合对象的元素,而无需了解底层数据结构。

迭代器模式应⽤⼴泛,但是⼤多数语⾔都已经内置了迭代器接⼝,不需要⾃⼰实现。


【基本结构】

迭代器模式包括以下⼏个重要角色

  • 迭代器接口Iterator :定义访问和遍历元素的接⼝, 通常会包括hasNext() ⽅法⽤于检查是否还有下⼀个元素,以及next() ⽅法⽤于获取下⼀个元素。有的还会实现获取第⼀个元素以及获取当前元素的⽅法。
  • 具体迭代器ConcreateIterator:实现迭代器接⼝,实现遍历逻辑对聚合对象进⾏遍历。
  • 抽象聚合类:定义了创建迭代器的接⼝,包括⼀个createIterator ⽅法⽤于创建⼀个迭代器对象。
  • 具体聚合类:实现在抽象聚合类中声明的createIterator() ⽅法,返回⼀个与具体聚合对应的具体迭代器

【简易实现--Java】

下面以Java代码作以说明:

**1. 定义迭代器接口:**通常会有检查是否还有下⼀个元素以及获取下⼀个元素的⽅法。

java 复制代码
// 迭代器接⼝
public interface Iterator{
    // 检查是否还会有下⼀个元素
    boolean hasNext();
    // 获取下⼀个元素
    Object next();
}

2. 定义具体迭代器:实现迭代器接口,遍历集合。

java 复制代码
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()⽅法,⽤于创建迭代器

java 复制代码
public interface Iterable {
    Iterator createIterator();
}

4. 实现具体聚合:创建具体的迭代器

java 复制代码
// 具体聚合
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);
    }
}
  1. 客户端使用
java 复制代码
/**
* @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());
        }
    }
}

【使用场景】

迭代器模式是⼀种通用的设计模式,其封装性强 ,简化了客户端代码,客户端不需要知道集合的内部结构,只需要关心迭代器和迭代接口 就可以完成元素的访问。但是引⼊迭代器模式会增加额外的类**,每增加⼀个集合类,都需要增加该集合对应的迭代器** ,这也会使得代码结构变得更加复杂。

许多编程语⾔和框架都使用了这个模式提供⼀致的遍历和访问集合元素的机制。下⾯是几种常见语⾔迭代器模式的实现。

1. Java语言

集合类(如ArrayList、LinkedList), 通过Iterator 接⼝,可以遍历集合中的元素。

java 复制代码
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());
}

2. Python语言

使用迭代器和⽣成器来实现迭代模式,iter() 和next() 函数可以⽤于创建和访问迭代器。

python 复制代码
elements = ["Element 1", "Element 2", "Element 3"]
iterator = iter(elements)

while True:
    try:
        element = next(iterator)
        print(element)
    except StopIteration:
        break

3. C++语言

C++中的STL提供了迭代器的⽀持, begin() 和end() 函数可以⽤于获取容器的起始和结束迭代器。

cpp 复制代码
#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;
}

4. JavaScript语言

ES6中新增了迭代器协议,使得遍历和访问集合元素变得更加方便。

javascript 复制代码
// 可迭代对象实现可迭代协议
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);
}

【编码部分】

1. 题目描述

小明是一位老师,在进行班级点名时,希望有一个学生名单系统,请你实现迭代器模式提供一个迭代器使得可以按顺序遍历学生列表。

2. 输入描述

第一行是一个整数 N (1 <= N <= 100), 表示学生的数量。接下来的 N 行,每行包含一个学生的信息,格式为 姓名 学号;

3. 输出描述

输出班级点名的结果,即按顺序遍历学生列表,输出学生的姓名和学号;

4. C++编程实例

cpp 复制代码
/**
* @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.

相关推荐
渣哥38 分钟前
原来 Java 里线程安全集合有这么多种
java
间彧1 小时前
Spring Boot集成Spring Security完整指南
java
间彧1 小时前
Spring Secutiy基本原理及工作流程
java
数据智能老司机2 小时前
精通 Python 设计模式——创建型设计模式
python·设计模式·架构
Java水解2 小时前
JAVA经典面试题附答案(持续更新版)
java·后端·面试
数据智能老司机3 小时前
精通 Python 设计模式——SOLID 原则
python·设计模式·架构
c8i4 小时前
django中的FBV 和 CBV
python·django
c8i4 小时前
python中的闭包和装饰器
python
洛小豆4 小时前
在Java中,Integer.parseInt和Integer.valueOf有什么区别
java·后端·面试
前端小张同学5 小时前
服务器上如何搭建jenkins 服务CI/CD😎😎
java·后端