设计模式:迭代器模式(Iterator)

news2024/11/26 8:23:32

设计模式:迭代器模式(Iterator)

  • 设计模式:迭代器模式(Iterator)
    • 模式动机
    • 模式定义
    • 模式结构
    • 时序图
    • 模式实现
    • 在单线程环境下的测试
    • 在多线程环境下的测试
    • 模式分析
    • 优缺点
    • 适用场景
    • 应用场景
    • 参考

设计模式:迭代器模式(Iterator)

迭代器模式(Iterator)属于行为型模式(Behavioral Pattern)的一种。

行为型模式(Behavioral Pattern)是对在不同的对象之间划分责任和算法的抽象化。

行为型模式不仅仅关注类和对象的结构,而且重点关注它们之间的相互作用。

通过行为型模式,可以更加清晰地划分类与对象的职责,并研究系统在运行时实例对象之间的交互。在系统运行时,对象并不是孤立的,它们可以通过相互通信与协作完成某些复杂功能,一个对象在运行时也将影响到其他对象的运行。

行为型模式分为类行为型模式和对象行为型模式两种:

  1. 类行为型模式:类的行为型模式使用继承关系在几个类之间分配行为,类行为型模式主要通过多态等方式来分配父类与子类的职责。
  2. 对象行为型模式:对象的行为型模式则使用对象的聚合关联关系来分配行为,对象行为型模式主要是通过对象关联等方式来分配两个或多个类的职责。根据“合成复用原则”,系统中要尽量使用关联关系来取代继承关系,因此大部分行为型设计模式都属于对象行为型设计模式。

模式动机

我们使用的聚合对象各种各样,比如vector、list、tree、map等等,既然是聚合,那就有访问其个体的需要。而遍历访问这个行为可能有深度优先、广度优先、顺序遍历、逆序遍历等等,迭代器的意义就是将这个行为抽离封装起来,这样客户端只需要调用合适的迭代器,来进行对应的遍历,而不用自己去实现这一行为。

模式定义

迭代器模式(Iterator)属于行为型模式。

迭代器模式(Iterator)提供一种方法顺序访问一个聚合对象中各个元素,而不暴露该对象的内部表示。通过迭代器,客户端可以顺序访问聚合对象的元素,而无需了解底层数据结构。

模式结构

迭代器模式(Iterator)包含如下角色:

  • 抽象聚合(Aggregate):抽象容器,定义存储、添加、删除聚合对象以及创建迭代器对象的接口。
  • 具体聚合(ConcreteAggregate):具体容器,实现内部不同结构,返回一个迭代器实例。
  • 抽象迭代器(Iterator): 定义访问和遍历聚合元素的接口。
  • 具体迭代器(ConcreteIterator): 实现抽象迭代器接口中的方法,完成对聚合对象的遍历,记录遍历的当前位置。

在这里插入图片描述

从上图中,我们可以看到具体容器和具体迭代器两者是相互调用的,也就是说容器调用了迭代器,然后通过迭代器调用了容器内部自身的方法来实现封装。

时序图

略。

模式实现

以 vector 为例,设计了模板类。示例代码如下:

抽象迭代器 Iterator.h:

#ifndef _ITERATOR_H_
#define _ITERATOR_H_

template<typename T>
class Iterator
{
public:
	// 第一个元素
	virtual T first() = 0;
	// 下一个元素
	virtual T next() = 0;
	// 是否到达容器的终点
	virtual bool isDone() = 0;
	// 获取当前元素的指针
	virtual T* currentItem() = 0;
};

#endif // !_ITERATOR_H_

具体迭代器 ConcreteIterator.h:

#ifndef _CONCRETE_ITERATOR_H_
#define _CONCRETE_ITERATOR_H_

#include <vector>
#include "Iterator.h"

template<typename T>
class ConcreteIterator : public Iterator<T>
{
private:
	std::vector<T> m_data;
	int index;

public:
	// 构造函数
	ConcreteIterator(std::vector<T> data) : m_data(data), index(0) {}

	T first()
	{
		return *m_data.begin();
	}
	T next()
	{
		if (isDone())
			return (T)0;
		return m_data[index++];
	}
	bool isDone()
	{
		if (index < m_data.size())
			return false;
		return true;
	}
	T* currentItem()
	{
		if (index < m_data.size())
			return &m_data[index];
		else
			return nullptr;
	}
};

#endif // !_CONCRETE_ITERATOR_H_

抽象聚合 Aggregate.h:

#ifndef _AGGREGATE_H_
#define _AGGREGATE_H_

#include "Iterator.h"
#include "Aggregate.h"

template<typename T>
class Aggregate
{
public:
	// 创建迭代器
	virtual Iterator<T>* createIterator() = 0;
};

#endif // !_AGGREGATE_H_

具体聚合 ConcreteAggregate.h:

#ifndef _CONCRETE_AGGREGATE_H_
#define _CONCRETE_AGGREGATE_H_

#include "ConcreteIterator.h"
#include "Aggregate.h"

template<typename T>
class ConcreteAggregate : public Aggregate<T>
{
private:
	std::vector<T> m_data;

public:
	// 构造函数
	ConcreteAggregate(std::vector<T> data) : m_data(data) {}

	Iterator<T>* createIterator()
	{
		return new ConcreteIterator<T>(m_data);
	}
};

#endif // !_CONCRETE_AGGREGATE_H_

在单线程环境下的测试

测试代码,也可以说是 client:

#include <iostream>
#include <vector>
#include <stdlib.h>

#include "ConcreteIterator.h"
#include "ConcreteAggregate.h"

using namespace std;

int main()
{
	vector<int> data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	// 创建容器和迭代器
	ConcreteAggregate<int>* aggregate = new ConcreteAggregate<int>(data);
	Iterator<int>* iterator = aggregate->createIterator();

	// 迭代器输出
	while (!iterator->isDone())
		cout << iterator->next() << " ";
	cout << endl;

	// 清除
	delete iterator;
	delete aggregate;
	iterator = nullptr;
	aggregate = nullptr;

	system("pause");
	return 0;
}

运行结果:

在这里插入图片描述

在多线程环境下的测试

略。

模式分析

  • 迭代器模式提供了一种统一的方式来遍历集合对象中的元素。
  • 它将遍历操作封装到一个独立的迭代器对象中,使得我们可以按照特定的方式访问集合中的元素。
  • 迭代器模式将集合对象和遍历操作分离开来,提高了代码的灵活性和可维护性。
  • 使用迭代器模式可以让我们用相同的方式遍历不同类型的集合对象,而不需要了解集合的内部结构。

优缺点

优点:

  1. 符合单一职责原则。将遍历行为抽离成单独的类。
  2. 符合开闭原则。如果需要增加新的遍历方式,只需实现一个新的具体迭代器即可,不需要修改原先聚合对象的代码。
  3. 简化了集合类的接口,使用者可以更加简单地遍历集合对象,而不需要了解集合内部结构和实现细节。
  4. 将集合和遍历操作解耦,使得我们可以更灵活地使用不同的迭代器来遍历同一个集合,根据需求选择不同的遍历方式。

缺点:

  1. 不适合每种场景:若对聚合对象只需要进行简单的遍历行为,那使用迭代器模式有些大材小用。
  2. 遍历效率降低:在某些情况下,使用迭代器模式可能会导致遍历效率降低,特别是使用外部迭代器时,需要手动进行迭代操作。
  3. 由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性。

适用场景

  1. 访问一个聚合对象的内容而无须暴露它的内部表示。
  2. 需要为聚合对象提供多种遍历方式。
  3. 减少与集合对象的耦合。
  4. 为遍历不同的聚合结构提供一个统一的接口。
  5. 提供一个便利的方法访问一个聚合对象中的每个元素。

应用场景

  1. 集合框架中的迭代器:C++ 的 STL 容器一般都有自己的迭代器。在Java中,集合包括List、Set、Map等等,每个集合类中都提供了一个获取迭代器的方法,例如List提供的iterator()方法、Set提供的iterator()方法等等。通过获取对应的迭代器对象,可以对集合中的元素进行遍历和访问。
  2. JDBC中的ResultSet对象:在Java中,如果需要对数据库中的数据进行遍历和访问,可以使用JDBC操作数据库。JDBC中,查询结果集使用ResultSet对象来表示,通过使用ResultSet的next()方法,就可以像使用迭代器一样遍历和访问查询结果中的数据。
  3. 文件读取:在Java中,我们可以使用BufferedReader类来读取文本文件。BufferedReader类提供了一个方法readLine()来逐行读取文件内容。实际上,BufferedReader在内部使用了迭代器模式来逐行读取文本文件的内容。
  4. Python 使用迭代器和⽣成器来实现迭代模式,iter() 和next() 函数可以⽤于创建和访问迭代器。
  5. JavaScript:ES6中新增了迭代器协议,使得遍历和访问集合元素变得更加方便。

参考

  1. https://zhuanlan.zhihu.com/p/678005837
  2. https://blog.csdn.net/zhaitianbao/article/details/130097933
  3. https://hermit.blog.csdn.net/article/details/123429647
  4. https://www.cnblogs.com/ybqjymy/p/17534782.html
  5. https://blog.csdn.net/qq_42764269/article/details/127382043
  6. https://blog.csdn.net/K1_uestc/article/details/135772598
  7. https://blog.csdn.net/weixin_45433817/article/details/131382881
  8. https://www.runoob.com/design-pattern/iterator-pattern.html

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

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

相关文章

第五百回 Get路由管理

文章目录 1. 概念介绍2. 使用方法2.1 普通路由2.2 命名路由 3. 示例代码4. 内容总结 我们在上一章回中介绍了"使用get显示Dialog"相关的内容&#xff0c;本章回中将介绍使用get进行路由管理.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在本章…

什么是分库分表

读写分离主要应对的是数据库读并发&#xff0c;没有解决数据库存储问题。试想一下&#xff1a;如果 MySQL 一张表的数据量过大怎么办? 答案当然是分库分表 什么是分库&#xff1f; 分库 就是将数据库中的数据分散到不同的数据库上&#xff0c;可以垂直分库&#xff0c;也可…

一二三应用开发平台使用手册——系统管理-系统参数系统日志-使用说明

系统参数 概述 通过配置化&#xff0c;可以提升系统灵活性和运维便利性。 配置化往往分为两大类&#xff0c;一类是偏技术层面的&#xff0c;如平台的发送邮件提醒的邮箱&#xff0c;相对固化&#xff0c;不会频繁调整&#xff0c;一般放在系统的配置文件里&#xff0c;如spr…

目标检测——印度车辆数据集

引言 亲爱的读者们&#xff0c;您是否在寻找某个特定的数据集&#xff0c;用于研究或项目实践&#xff1f;欢迎您在评论区留言&#xff0c;或者通过公众号私信告诉我&#xff0c;您想要的数据集的类型主题。小编会竭尽全力为您寻找&#xff0c;并在找到后第一时间与您分享。 …

MySQL前缀索引、脏页和干净页、COUNT(*)讨论、表删除内存问题

文章目录 如何加索引如何给身份证号添加索引 SQL语句变慢脏页 (Dirty Pages)干净页 (Clean Pages)为何区分脏页和干净页处理脏页管理策略 flush如何控制 为什么删除表数据后表文件大小不变问题背景核心原因数据存储方式参数影响 解决方案1. 调整innodb_file_per_table设置2. 使…

2.4 输入和显示

本节必须掌握的知识点&#xff1a; 示例五源代码 代码分析 汇编解析 2.4.1 示例五 ■格式化输入函数scanf scanf函数可以从键盘读取输入的信息。scanf函数同样可以像printf函数那样&#xff0c;通过转换说明“%d”来限制函数只能读取十进制数。scanf函数的参数为可变参数…

雷军-2022.8小米创业思考-6-互联网七字诀之快:天下武功,唯快不破;快不是目的,快是手段;不要用战术上的勤奋掩盖战略上的懒惰。

第六章 互联网七字诀 专注、极致、口碑、快&#xff0c;这就是我总结的互联网七字诀&#xff0c;也是我对互联网思维的高度概括。 快 我们期待非常多的快&#xff0c;比如研发进展快、库存周转快、资金回笼快等等。但在这里&#xff0c;我们集中讨论的是公司在业务发展和面对…

【5分钟学会一个知识点】01.Elasticsearch基本操作-增删改查

目录 【5分钟学会一个知识点-探索现代搜索与分析引擎的魅力】01.Elasticsearch基本操作-增删改查1.基本操作1.1索引操作1.2文档操作1.3查询1.4修改数据1.5查询1.5.1条件查询1.5.1.1遍历所有的索引1.5.1.2查询某个索引1.5.1.3条件查询1&#xff1a;使用GET url传参数1.5.1.4条件…

18、案例实战:上亿请求轻松应对,看年轻代垃圾回收如何助力电商性能飞跃!

18.1、背景引入 我们通常会通过案例分析&#xff0c;来指导大家如何在不同的场景下&#xff0c;预测系统的内存使用模型。我们需要合理地调整新生代、老年代、Eden和Survivor各个区域的内存大小&#xff0c;然后尽可能地优化参数&#xff0c;以减少新生代对象进入老年代的情况…

An 2024下载

An2024下载&#xff1a; 百度网盘下载https://pan.baidu.com/s/1cQQCFL16OUY1G6uQWgDbSg?pwdSIMS Adobe Animate 2024&#xff0c;作为Flash技术的进化顶点&#xff0c;是Adobe匠心打造的动画与交互内容创作的旗舰软件。这款工具赋予设计师与开发者前所未有的创意自由&#x…

火绒安全原理、用法、案例和注意事项

火绒安全是一款功能强大的安全软件&#xff0c;它采用了先进的安全技术和算法&#xff0c;通过实时监测、恶意代码识别、防火墙功能、沙箱技术和网络保护等多种手段&#xff0c;为用户提供全面的计算机安全防护。 1.为什么选用火绒安全&#xff1f; 火绒安全是一款优秀的安全软…

用lobehub打造一个永久免费的AI个人助理

Lobe Chat是一个开源的高性能聊天机器人框架&#xff0c;它被设计来帮助用户轻松创建和部署自己的聊天机器人。这个框架支持多种智能功能&#xff0c;比如语音合成&#xff08;就是让机器人能说话&#xff09;&#xff0c;还能理解和处理多种类型的信息&#xff0c;不仅限于文字…

AI图书推荐:用GPT-4进行预测分析的实用指南

《用GPT-4进行预测分析的实用指南》&#xff08;A Practical Guide to Predictive Analytics with GPT-4&#xff09;为读者提供了一个全面的指南&#xff0c;介绍了如何利用GPT-4的强大预测能力&#xff0c;从理解预测分析的基础&#xff0c;到掌握GPT-4的使用&#xff0c;再到…

基于yolov5+gradio目标检测演示系统设计

YOLOv5与Gradio&#xff1a;目标检测可视化展示的新篇章 随着人工智能技术的深入发展&#xff0c;目标检测已成为现代智能应用中的一项关键技术。YOLOv5&#xff0c;作为目标检测领域的杰出代表&#xff0c;凭借其出色的实时性和准确性&#xff0c;赢得了广泛的认可和应用。而…

电力场景设备漏油检测数据集VOC+YOLO格式338张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;338 标注数量(xml文件个数)&#xff1a;338 标注数量(txt文件个数)&#xff1a;338 标注类别…

数据缓存,可以尝试RocksDB了

shigen坚持更新文章的博客写手&#xff0c;擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。记录成长&#xff0c;分享认知&#xff0c;留住感动。 个人IP&#xff1a;shigen shigen在最近的学习中&#xff0c;接触到了一款新的缓存数据库RocksDB&#xff…

SQL语句优化技巧

目录 1、sql语句规范 2、sql语句优化 1、sql语句规范 MySQL在Linux系统下数据库名&#xff0c;表名&#xff0c;存储过程名&#xff0c;函数名称&#xff0c;触发器名称等区分大小写&#xff0c;列名不区分大小写&#xff0c;原因是这些操作系统下文件名称区分大小写。 MySQL…

LNMP 环境下 Nginx 1.26.0 开启 HTTP/3 QUIC 支持

前几天 Nginx 1.26.0 主线版发布了&#xff0c;明月总算抽出时间更新了&#xff0c;那么自然的也要尝试一下开启 HTTP/3 QUIC 支持了&#xff0c;今天就给大家分享一下。对于我们的网站来说开启 HTTP/3 QUIC 最大的好处是页面载入速度的提升&#xff0c;尤其是在支持 HTTP/3 QU…

安卓模拟器怎么修改ip地址

最近很多老铁玩游戏的&#xff0c;想多开模拟器一个窗口一个IP&#xff0c;若模拟器窗口开多了&#xff0c;IP一样会受到限制&#xff0c;那么怎么更换自己电脑手机模拟器IP地址呢&#xff0c;今天就教大家一个修改模拟器IP地址的方法&#xff01;废话不多说&#xff0c;直接上…

牛客NC363 开锁【中等 BFS Java/Go/PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/e7cbabbf7e0a41ec98055ee5f3d33bbe https://www.lintcode.com/problem/796 思路 Java代码 import java.util.*;public class Solution {/*** 代码中的类名、方法名、参数名已经指定&#xff0c;请勿修改&#x…