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

【声明】本题目来源于卡码网(https://kamacoder.com/)

【提示:如果不想看文字介绍,可以直接跳转到C++编码部分


设计模式大纲】


【简介】

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

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

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


【基本结构】

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

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


【简易实现--Java】

        下面以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;}@Overridepublic boolean hasNext() {return index < elements.size();}@Overridepublic 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;}@Overridepublic 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());}}
}

【使用场景】

        迭代器模式是⼀种通用的设计模式,其封装性强,简化了客户端代码,客户端不需要知道集合的内部结构,只需要关心迭代器和迭代接口就可以完成元素的访问。但是引⼊迭代器模式会增加额外的类,每增加⼀个集合类,都需要增加该集合对应的迭代器,这也会使得代码结构变得更加复杂。
        许多编程语⾔和框架都使用了这个模式提供⼀致的遍历和访问集合元素的机制。下⾯是几种常见语⾔迭代器模式的实现。

1. Java语言

        集合类(如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());
}

2. Python语言

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

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() 函数可以⽤于获取容器的起始和结束迭代器。

#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中新增了迭代器协议,使得遍历和访问集合元素变得更加方便。

// 可迭代对象实现可迭代协议
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++编程实例

/**
* @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);}// 迭代器接口函数重载  返回值为迭代器基类的指针 模板类型为StudentIterator<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.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/644314.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

docker-compose搭建redis集群

这里用docker-compose在一台机器搭建三主三从&#xff0c;生产环境肯定是在多台机器搭建&#xff0c;否则一旦这台宿主机挂了&#xff0c;redis集群全挂了&#xff0c;依然是单点故障。同时&#xff0c;受机器性能极限影响&#xff0c;其并发也上不去&#xff0c;算不上高并发。…

web开发学习笔记(14.mybatis基于xml配置)

1.基本介绍 2.基本使用 在mapper中定义 在xml中定义&#xff0c;id为方法名&#xff0c;resultType为实体类的路径 在测试类中写 3. 动态sql&#xff0c;if和where关键字 动态sql添加<where>关键字可以自动产生where和过滤and或者or关键字 where关键字可以动态生成whe…

kafka(一)快速入门

一、kafka&#xff08;一&#xff09;是什么&#xff1f; kafka是一个分布式、支持分区、多副本&#xff0c;基于zookeeper协调的分布式消息系统&#xff1b; 二、应用场景 日志收集&#xff1a;一个公司可以用Kafka收集各种服务的log&#xff0c;通过kafka推送到各种存储系统…

Zabbix 整合 Prometheus:案例分享与操作指南

一、简介 Zabbix 和 Prometheus 都是流行的开源监控工具&#xff0c;它们各自具有独特的优势。Zabbix 主要用于网络和系统监控&#xff0c;而 Prometheus 则专注于开源的分布式时间序列数据库。在某些场景下&#xff0c;将这两个工具整合在一起可以更好地发挥它们的优势&#…

vue3源码(二)reactiveeffect

一.reactive与effect功能 reactive方法会将对象变成proxy对象&#xff0c; effect中使用reactive对象时会进行依赖收集&#xff0c;稍后属性变化时会重新执行effect函数。 <div id"app"></div><script type"module">import {reactive,…

从零学Java MySQL

MySQL 文章目录 MySQL初识数据库思考&#xff1a;1 什么是数据库&#xff1f;2 数据库管理系统 初识MySQLMySQL卸载MySQL安装1 配置环境变量2 MySQL目录结构及配置文件 连接MySQL数据库基本命令MySQL基本语法&#xff1a;1 查看MySQL服务器中所有数据库2 创建数据库3 查看数据库…

leetcode—课程表 拓扑排序

1 题目描述 你这个学期必须选修 numCourses 门课程&#xff0c;记为 0 到 numCourses - 1 。 在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出&#xff0c;其中 prerequisites[i] [ai, bi] &#xff0c;表示如果要学习课程 ai 则 必须 先学习课程 …

《WebKit 技术内幕》学习之五(2): HTML解释器和DOM 模型

2.HTML 解释器 2.1 解释过程 HTML 解释器的工作就是将网络或者本地磁盘获取的 HTML 网页和资源从字节流解释成 DOM 树结构。 这一过程中&#xff0c;WebKit 内部对网页内容在各个阶段的结构表示。 WebKit 中这一过程如下&#xff1a;首先是字节流&#xff0c;经过解码之…

ORBSLAM3安装

0. C11 or C0x Compiler sudo apt-get install gccsudo apt-get install gsudo apt-get install build-essentialsudo apt-get install cmake1. 依赖 在该目录终端。 1. 1.Pangolin git clone https://github.com/stevenlovegrove/Pangolin.git sudo apt install libglew-d…

Python基础第九篇(Python可视化的开发)

文章目录 一、json数据格式&#xff08;1&#xff09;.转换案例代码&#xff08;2&#xff09;.读出结果 二、pyecharts模块介绍三、pyecharts模块入门&#xff08;1&#xff09;.pyecharts模块安装&#xff08;2&#xff09;.pyecharts模块操作&#xff08;1&#xff09;.代码…

C++力扣题目509--斐波那契数 70--爬楼梯 746--最小花费爬楼梯

509. 斐波那契数 力扣题目链接(opens new window) 斐波那契数&#xff0c;通常用 F(n) 表示&#xff0c;形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始&#xff0c;后面的每一项数字都是前面两项数字的和。也就是&#xff1a; F(0) 0&#xff0c;F(1) 1 F(n) F(n -…

了解WPF控件:PrintDialog常用属性与用法(八)

掌握WPF控件&#xff1a;熟练常用属性&#xff08;八&#xff09; PrintDialog -一个对话框&#xff0c;用于在打印文档时显示打印设置参数供用户选择并确认。通过该控件&#xff0c;用户可以选择打印机、打印的范围、打印的份数、打印质量等。 常用属性描述CurrentPageEnab…

制作编写使用说明书:在结构、风格与内容方面需要注意什么?

如今&#xff0c;一个清晰、简洁、易于理解的使用说明书不仅能够帮助用户正确地使用产品&#xff0c;还能提升用户体验并树立品牌形象。而制作编写一份优质的使用说明书需要我们在结构、风格与内容三个方面下功夫。那么在制作编写使用说明书时需要注意哪些关键要素呢&#xff1…

【JavaWeb】日程管理系统 项目搭建 第二期

文章目录 一、数据库准备二、导入依赖 与 JDBC工具类三、pojo包处理四、daodao包工具类 五、service六、controllerservlet 基类 反射 七、加密工具类 MD5八、页面文件九、业务代码9.1 注册业务处理9.2 登录业务处理 总结 一、数据库准备 创建数据库&#xff1a; SET NAMES …

骨传导耳机综评:透视南卡、韶音和墨觉三大品牌的性能与特点

在当前的蓝牙音频设备领域中&#xff0c;骨传导蓝牙运动耳机以其出色的安全特性和舒适的体验&#xff0c;受到了健身爱好者们的广泛好评。这类耳机不同于我们常见的入耳式耳机&#xff0c;它的工作方式是直接通过振动将声音传递到用户的耳骨中&#xff0c;这样既可以享受音乐&a…

【nowcoder】链表的回文结构

牛客题目链接 链表的回文结构 /* struct ListNode {int val;struct ListNode *next;ListNode(int x) : val(x), next(NULL) {} };*/ #include <cstdlib> // 建议大伙自己对照我的代码画下图&#xff0c;假设A链表是&#xff1a;1 2 3 2 1 class PalindromeList { publi…

【学网攻】 第(7)节 -- 生成树配置

文章目录 【学网攻】 第(1)节 -- 认识网络【学网攻】 第(2)节 -- 交换机认识及使用【学网攻】 第(3)节 -- 交换机配置聚合端口【学网攻】 第(4)节 -- 交换机划分Vlan【学网攻】 第(5)节 -- Cisco VTP的使用【学网攻】 第(6)节 -- 三层交换机实现VLAN间路由 前言 网络已经成为…

vscode 如何指定启动文件?

launch.json 里面可以指定&#xff0c;launch.json 在打开文件夹的时候可以创建&#xff0c;或者手动创建

不合格机器人工程讲师再读《悉达多》-2024-

一次又一次失败的经历&#xff0c;让我对经典书籍的认同感越来越多&#xff0c;越来越觉得原来的自己是多么多么的无知和愚昧。 ----zhangrelay 唯物也好&#xff0c;唯心也罢&#xff0c;我们都要先热爱这个世界&#xff0c;然后才能在其中找到自己所热爱的事业。 ----zh…

vue2项目打包到测试环境之后报错require is not defined

配置打包命令npm run build:test到测试环境之后报错&#xff0c;打包到生产环境没有问题&#xff0c;查找了项目中的require引入似乎也没啥有问题的地方&#xff0c;所以排除是require的原因 环境变量文件&#xff1a; 打包指令&#xff1a; 解决办法&#xff1a; 将.env.tes…