深圳 福田 网站建设/百度上搜索关键词如何在首页
设计模式是代码重构的最终目标,在程序设计中有效的运用这项技术,可以大大提高代码的可读性和可维护性。使整个程序设计结构趋向精致完美。在我维护的FileBrowser模块中可以针对以下方面
应用相应的模式。
1. 使用策略模式来处理文件夹扫描操作
作为网络文件浏览器,FileBrowser中自然有很多对文件夹的操作。包括计算文件夹信息,删除文件夹等,这些操作采用的都是标准的文件夹遍历的代码,只是对于各文件/文件夹进行不同的处理而已,基本代码如下:
HANDLE fp = FindFirstFile(szLocalFName, &fd);
while(TRUE)
{
if(fd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
{
Handle the folder…
}
Else
{
Handle the file…
}
if(!FindNextFile(fp, &Fd))
break;
}
显而易见,这里很适合使用策略模式:定义一个通用的扫描函数,定义策略类架构,使每个策略对象对应一个文件处理方法。这样可以避免模块中大量的相似的文件夹遍历的代码,使之简洁明了,而且更加容易扩充。
我们看一下策略模式的定义:
结构图:
基于这个思想,我设计了以下文件夹扫描结构:
class folder_handler
{
public:
folder_handler(const tstring& root) : m_root(root){}
virtual ~folder_handler(){}
virtual bool handle_folder
(const tstring&, const WIN32_FIND_DATA&){ return true; }
virtual bool handle_file(const tstring&, const WIN32_FIND_DATA&)
{ return true; }
virtual bool folder_first(){ return true; }
protected:
tstring m_root;
};
void scan_folder(const tstring& folder_path, folder_handler& h)
{
tstring child_path(_T(""));
string find_name = folder_path + _T(“//*.*”);
WIN32_FIND_DATA fd = {0};
HANDLE hFindFile = FindFirstFile(find_name.c_str(), &fd);
if (INVALID_HANDLE_VALUE == hFindFile)
{
cout << "Cann't access folder " << folder_path << endl;
return;
}
// 先处理父文件夹
if (h.folder_first())
{
h.handle_folder(folder_path);
}
do
{
if (_T('.') == fd.cFileName[0])
{
continue;
}
child_path = folder_path + _T("//") + fd.cFileName;
if (FILE_ATTRIBUTE_DIRECTORY & fd.dwFileAttributes)
{
scan_folder(child_path, h);
}
else
{
m_numfiles++;
m_foldersize+=
MAKELONGLONG(fd.nFileSizeLow, fd.nFileSizeHigh);
h.handle_file(child_path, fd);
}
} while(FindNextFile(hFindFile, &fd));
FindClose(hFindFile);
// 后处理父文件夹
if (!h.folder_first())
{
h.handle_folder(folder_path);
}
}
这样我们想对文件夹做某种特定操作的时候,只需要定义一个新类,指定对子文件/子文件夹的特定操作即可,而不需要关注其遍历过程的细节,耦合度非常的低。例如我们想删除文件夹和扫描文件夹同步信息的话那么就可以定义以下两个类。
class folder_deleter : public folder_handler
{
public:
folder_deleter(const tstring& parent_folder)
: folder_handler(parent_folder)
{
}
virtual bool handle_folder
(const tstring& folder_path, const WIN32_FIND_DATA&)
{
if (!::RemoveDirectory(folder_path.c_str()))
{
_tcout << _T("Fail to remove the folder ") << folder_path << endl;
_tcout << _T("The error code ") << ::GetLastError() << endl;
return false;
}
return true;
}
virtual bool handle_file
(const tstring& file_path, const WIN32_FIND_DATA&)
{
if (!::DeleteFile(file_path.c_str()))
{
_tcout << _T("Fail to delete the file ") << file_path << endl;
_tcout << _T("The error code ") << ::GetLastError() << endl;
return false;
}
return true;
}
virtual bool folder_first(){ return false; }
};
class folder_inforecorder : public folder_handler
{
typedef struct
{
DWORD attrib;
LONGLONG size;
LONGLONG modified_time;
tstring path;
}file_info;
typedef vector<file_info> file_infos;
typedef file_infos::iterator fis_iter;
typedef file_infos::const_iterator fis_citer;
public:
folder_inforecorder(const tstring& parent_folder)
: folder_handler(parent_folder) {}
~folder_inforecorder(){}
virtual bool handle_file
(const tstring& folder_name, const WIN32_FIND_DATA& fd)
{
file_info fi;
fi.attrib = fd.dwFileAttributes;
fi.size = MAKELONGLONG(fd.nFileSizeLow, fd.nFileSizeHigh);
fi.modified_time =
MAKELONGLONG(fd.ftLastWriteTime.dwLowDateTime,
fd.ftLastWriteTime.dwHighDateTime);
tstring file_path = folder_name + _T("//") + fd.cFileName;
const tstring parentfolder = m_root + _T("//");
tstring::size_type pos = file_path.find(parentfolder);
if (tstring::npos == pos)
fi.path = file_path.c_str();
else
fi.path = file_path.substr(pos + parentfolder.size(),
tstring::npos).c_str();
m_FileInfos.push_back(fi);
return true;
}
public:
file_infos m_FileInfos;
};
使用的时候调用如下代码即可:
scanfolder scan
// 删除路径
scan.run_scan(folder_path, folder_deleter());
folder_inforecorder fir;
// 扫描路径文件信息
scan.run_scan(folder_path, fir);
2. 使用Command命令模式实现文件操作的Undo/Redo
FileBrowser对于文件操作的目前不支持Undo/Redo功能,用户所有的操作都是不可逆的,所以对于用户来说存在一定的操作风险以及不便。我们可以利用Command命令模式来实现这个功能:
将用户的命令封装成不同的对象,支持统一的接口Execute /UnExecute;定义一个命令管理类,支持Undo/Redo接口,维护一个执行命令对象链;每当用户完成一个操作之后,便生成相应的命令对象,将其加入命令对象链尾部,并将当前命令对象迭代器指向它。执行Undo/Redo功能时,根据当前命令对象迭代器调用当前命令对象Execute /UnExecute接口,并将当前命令对象迭代器在命令对象链中做相应的移动。
命令对象链操作示意图
当前命令对象迭代器 |
命令对象链 |
Figrure 3-1
命令对象类体系图
大致代码如下:
class CCommand
{
public:
CCommand(){}
virtual ~CCommand(){}
virtual void Execute() = 0;
virtual void UnExecute() = 0;
};
class CCommandManager
{
public:
CCommandManager() : m_CurPos(m_cCommandList.end()){}
virtual ~CCommandManager(){ Clear(); }
void AddCommand(CCommand* pcCommand)
{
ASSERT(pcCommand);
m_cCommandList.erase(m_cCommandList.begin(), m_CurPos);
m_cCommandList.insert(m_CurPos, pcCommand);
m_CurPos--;
}
BOOL CanUndo()
{
return (m_cCommandList.size() > 0 &&
m_CurPos != m_cCommandList.end());
}
BOOL CanRedo();
{
return (m_cCommandList.size() > 0
&& m_CurPos != m_cCommandList.begin());
}
CCommand* Undo()
{
CCommand* pcCommand = NULL;
if (CanUndo())
{
pcCommand = *m_CurPos;
ASSERT(pcCommand);
pcCommand->UnExecute();
m_CurPos++;
}
return pcCommand;
}
CCommand* Redo()
{
CCommand* pcCommand = NULL;
if (CanRedo())
{
m_CurPos--;
pcCommand = *m_CurPos;
ASSERT(pcCommand);
pcCommand->Execute();
}
return pcCommand;
}
void Clear();
private:
typedef list<CCommand*> commands;
typedef commands::iterator commands_iter;
commands m_cCommandList;// 命令对象指针容器
commands_iter m_CurPos;// 当前命令对象迭代器
};
比如我们想支持文件名命名操作Undo/Redo的话,定义以下类即可
class CCommand_Rename
{
public:
CCommand_Rename (){}
virtual ~CCommand_Rename (){}
virtual void Execute()
{
_trename(m_newfilename, m_oldfilename)
}
virtual void UnExecute()
{
_trename(m_oldfilename, m_newfilename);
}
private:
tstring m_oldfilename, m_newfilename;
};
3. 使用智能指针来管理内存(代理模式).
在程序中维护大量的指针,是非常头疼的问题。我们经常会忘记释放某些已分配内存的指针,特别是在一些复杂逻辑和很多出口的函数中,从而造成一些内存漏洞。而且有的地方我们为了保证释放内存,不得不写很多冗余的代码或者借助于一些不良的语法。
我们来看如下逻辑:
1) 先对指针A分配内存,A分配内存如果成功,那么对指针B分配内存,如果失败返回.
2) 如果B分配失败那么释放指针A返回,如果成功。那么对指针C分配内存.
3) 如果C分配失败那么释放指针A,B返回。如果成功对指针D分配内存.
4) 如果D分配失败那么释放指针A,B,C返回
…
一般的代码可能是这样
CA* A = new CA;
If (!A) return;
A->f1()
CB* B = new CB;
If (!B)
{
delete A;
return 0;
}
B-> f2();
CC* C = new CC;
If (!C)
{
delete A;
delete B;
return 0;
}
C-> f3();
CD* D = new CD;
If (!D)
{
delete A;
delete B;
delete C;
return 0;
}
…
这样的代码看上去非常的罗嗦,增加了代码阅读的困难,而且很容易遗漏一些内存释放的语句。
而有的程序员为了避免啰嗦,不得不借助于“goto”语句。
CA* A = NULL;
CB* B = NULL;
CC* C = NULL;
CD* D = NULL;
A = new CA;
if (!A) return 0;
A-> f1();
B = new CB;
if (!B)
{
goto CLEANUP;
}
B-> f2();
C = new CC;
if (!C)
{
goto CLEANUP;
}
C-> f3();
D = new CD;
if (!D)
{
goto CLEANUP;
}
…
CLEANUP:
if(A) delete A;
if(B) delete B;
if(C) delete C;
return 0;
但是goto语句早就已经是臭名昭著,其危害性很多文章里都有详细的描述,因此应该尽量避免,我们这里可以利用智能指针来避免这种尴尬。
auto_ptr<CA> A(new CA);
if (!&A) return 0;
A->f1();
auto_ptr<CB> B(new CB);
if (!&B) return 0;
B->f2();
auto_ptr<CC> C(new CC);
if (!&C) return 0;
C->f3();
auto_ptr<CD> D(new CD);
if (!&D) return 0;
…
这样代码简洁得多,而且由于它是在函数退出时,弹栈调用析构函数对所代理的指针进行删除,所以不会存在任何内存漏洞。
单件模式结构图:
4. 使用单件模式来管理资源
作为一个GUI程序,FileBrowser自然会和很多资源打交道,
目前这部分逻辑实现的不是很理想。有的地方通过全局变量有的是通过全局函数来访问资源.感觉上程序风格不是很统一,我们应该尽量避免使用全局变量。另外调用全局函数则每次都要加载释放资源动态库,比较的冗余低效。因为资源这块对于模块来讲只有唯一一个实例,而且可以被整个系统调用。所以可以使用单件模式来管理它。
定义一个资源管理管理类,保证其只有一个实例,模块中所有资源调用都是通过调用它的接口,结构图如下:
大致代码如下:
class CResManager
{
protected:
CResManager (){ LoadResouce(); }
~ CResManager (){FreeResouce (); }
public:
static CResManager& Instance()
{
static CResManager instance;
return instance;
}
void FsLoadString(UINT idString, LPTSTR lptsBuffer, DWORD dwLen);
void FsLoadBitMap(…);
void FsLoadMenu(HMENU* phMenu, UINT idMenu);
…
private:
void LoadResouce(){…}
void FreeResouce(){…}
private:
HINSTANCE m_hRes;
}
这样用户想读取一个字符串的话,调用以下语句即可
CResManager::Instance().FsLoadString(…);
整个模块的资源调用就显得统一简洁高效。
5. 使用备忘录模式来实现本地/远程目录的“前进/后退”功能
Windows自带的浏览器支持前进/后退的功能,用户可以来回浏览刚才访问过的路径,而不需要记住并敲入路径名,很是方便。其实利用备忘录模式,可以很容易的在FileBrowser中加入这一功能。
备忘录模式的机制在于定义一个对象状态的结构,当对对象进行操作之前,保存对象状态,撤销操作时根据保存的对象状态恢复此对象。这个描述看上去很像命令模式,不过命令模式保存的是对对象的操作而不是对象状态。
由于我们只要保存的文件夹路径这一单一信息,所以直接可以设置一个字符串链表即可,每次用户浏览新的路径,将当前路径名字符串保存到路径链表,并设置当前路径迭代器指向此字符串。用户前进/后退时,设置浏览器当前路径为路径迭代器所指向路径,并对路径迭代器做相应的调整。
路径链表操作示意图:
当前路径迭代器 |
路径字符串链表 |
大致代码如下:
class CPathControl
{
public:
CPathControl(void) : m_bInitialize(false) {}
~CPathControl(void){}
void CPathControl::Initialize(const tstring& path)
{
ASSERT(m_cPathList.empty());
m_cPathList.push_back(path);
m_CurPos = m_ PathList.begin();
m_bInitialize = true;
}
void AddNewPath(const tstring& path)
{
ASSERT(m_bInitialize);
m_CurPos = m_ cPathList.insert(++m_CurPos, path);
}
void GetCurPath(tstring& path)
{
ASSERT(m_bInitialize);
if (m_cPathList.size() > 0 && m_CurPos != m_cPathList.end())
(*m_CurPos).swap(path);.
}
BOOL CanMoveLast(void)
{
return (m_cPathList.size() > 0 && m_CurPos != m_cPathList.begin());
}
BOOL CanMoveNext(void)
{
list<st_viewinfo>::iterator iter = m_CurPos;
return (m_cPathList.size() > 0 && ++iter != m_cPathList.end());
}
void LastView(void)
{
if (!CanMoveLast())
m_CurPos--;
}
void NextView(void)
{
if (CanMoveNext())
m_CurPos++;
}
public:
list<tstring> m_cPathList;
list<tstring>::iterator m_CurPos;
private:
bool m_bInitialize;
};
class CFsSpDoc
{
…
Public:
void SetNewPath(const tstring& path)
{
m_cPathControl. AddNewPath(path);
BrowsePath(path);//浏览该路径
}
void Forward()
{
m_cPathControl.NextView();
tstring path(_T(“”));
m_cPathControl.GetPath(path);
BrowsePath(path); //浏览该路径
}
void Backward()
{
m_cPathControl.LastView();
tstring path(_T(“”));
m_cPathControl.GetPath(path);
BrowsePath(path);
}
…
private:
CPathControl m_cPathControl;
}
相关文章:

设计模式在FileBrowser中的几个应用
设计模式是代码重构的最终目标,在程序设计中有效的运用这项技术,可以大大提高代码的可读性和可维护性。使整个程序设计结构趋向精致完美。在我维护的FileBrowser模块中可以针对以下方面 应用相应的模式。 1. 使用策略模式来处理文件夹扫描操作 作为网…...

【JavaEE进阶】——Spring AOP
目录 🚩Spring AOP概述 🚩Spring AOP快速⼊⻔ 🎓引入AOP依赖 🎓编写AOP程序 🚩Spring AOP 详解 🎓Spring AOP核⼼概念 🎓通知类型 🎓PointCut 🎓切⾯优先级 Ord…...

Python - conda使用大全
如何使用Conda? 环境 创建环境 conda create -n spider_env python3.10.11查看环境 conda env listconda info -e激活环境 conda activate spider_env退出环境 conda deactivate删除环境 conda env remove -n spider_env包 导出包 说明:导出当前虚拟…...

ASPICE在汽车软件开发中的作用
ASPICE是一个专门为汽车软件开发过程而设计的评估和改进框架。它基于ISO/IEC 15504标准,为汽车供应商提供了一个评估和改进其软件开发流程的方法。ASPICE的目标是确保软件开发过程的一致性和可预测性,从而提高软件的质量和可靠性。 ASPICE的实施对汽车软…...

亚马逊云科技 re:Inforce 2024中国站大会
亚马逊云科技 re:Inforce 2024中国站大会 - 生成式AI时代的全面安全,将于7月25日本周四在北京富力万丽酒店揭幕...

Lottie:动态动画的魔法棒
文章目录 引言官网链接Lottie 的原理基础使用1. 导出动画2. 引入 Lottie 库3. 加载和播放动画 高级使用1. 动画控制2. 交互性3. 自定义动画例子:交互式按钮动画 优缺点优点缺点 结语 引言 Lottie 是 Airbnb 开源的一个动画库,它允许设计师在 Adobe Afte…...

IPython使用技巧整理
IPython 是一个增强的 Python 交互式 shell,它提供了许多便利的功能,比如自动补全、魔术命令、对象内省等。以下是 IPython 的一些使用技巧和示例,结合您提供的列表数据,我将给出一些相关的使用示例。 1. 自动补全(Tab…...

C#数组复习
一、一维数组 using System.Collections; using System.Collections.Generic; using UnityEngine;public class ShuZu : MonoBehaviour {#region 知识点一 基本概念//数组是存储一组相同类型数据的集合//数组分为 一维、二维、交错数组//一般情况 一维数组 就简称为数组#en…...

无人机之在农业上的用途
随着无人机技术的发展,农业现代化也迎来了崭新局面,田间随处可见无人机矫健的身影。当农业遇上科技,变革正悄然进行。农业无人机主要应用于农业、种植业、林业等行业。在使用过程中,其功能和作用并不单一,一般用于种植…...

opengaussdb在oepnEuler上安装
安装前提: 软件环境:openEuler 20.03LTS 个人开发者最低配置2核4G,推荐配置4核8G 数据库版本:openGauss-5.0.2-openEuler-64bit-all.tar.gz 数据库下载地址: https://docs-opengauss.osinfra.cn/zh/docs/5.0.0/docs/In…...

一些和颜色相关网站
1.中国传统色 2.网页颜色选择器 3.渐变色网站 4.多风格色卡生成 5.波浪生成 6.半透明磨砂框 7.色卡组合...

Linux系统编程-文件系统
目录 什么是Linux文件系统 文件系统的职责 存储介质抽象 inode:文件系统的核心 文件分配策略 目录结构 文件系统布局 日志和恢复机制 目录权限 粘滞位(t位): 硬链接和符号链接 硬链接的特点: 创建硬链接: 符号链接的…...

【解决】ubuntu20.04 root用户无法SSH登陆问题
Ubuntu root用户无法登录的问题通常可以通过修改SSH配置文件和系统登录配置来解决。 修改SSH配置文件 sudo vim /etc/ssh/sshd_config 找到 PermitRootLogin 设置,并将其值更改为 yes 以允许root用户通过SSH登录 保存并关闭文件之后,需要重启SSH服务…...

(前缀和) LeetCode 238. 除自身以外数组的乘积
一. 题目描述 原题链接 给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&…...

【JVM基础05】——组成-能不能解释一下方法区?
目录 1- 引言:方法区概述1-1 方法区是什么?(What)1-2 为什么用方法区?方法区的作用 (Why) 2- ⭐核心:详解方法区(How)2-1 能不能解释一下方法区?2-2 元空间内存溢出问题2-3 什么是常量池?2-4 运行时常量池 …...

前端:Vue学习-3
前端:Vue学习-3 1. 自定义指令2. 插槽2.1 插槽 - 后备内容(默认值)2.2 插槽 - 具名插槽2.3 插槽 - 作用域插槽 3. Vue - 路由3.1 路由模块封装3.2 声明式导航 router-link 高亮3.3 自定义匹配的类名3.4 声明式导肮 - 跳转传参3.5 Vue路由 - 重…...

npm 安装报错(已解决)+ 运行 “wue-cli-service”不是内部或外部命令,也不是可运行的程序(已解决)
首先先说一下我这个项目是3年前的一个项目了,中间也是经过了多个人的修改惨咋了布置多少个人的思想,这这道我手里直接npm都安装不上,在网上也查询了多种方法,终于是找到问题所在了 问题1: 先是npm i 报错在下面图片&…...

江苏科技大学24计算机考研数据速览,有专硕复试线大幅下降67分!
江苏科技大学(Jiangsu University of Science and Technology),坐落在江苏省镇江市,是江苏省重点建设高校,江苏省人民政府与中国船舶集团有限公司共建高校,国家国防科技工业局与江苏省人民政府共建高校 &am…...

20分钟上手新版Skywalking 9.x APM监控系统
Skywalking https://skywalking.apache.org/ Skywalking是专为微服务、云原生和基于容器的(Kubernetes)架构设计的分布式系统性能监控工具。 Skywalking关键特性 ● 分布式跟踪 ○ 端到端分布式跟踪。服务拓扑分析、以服务为中心的可观察性和API仪表板。…...

【07】LLaMA-Factory微调大模型——微调模型导出与微调参数分析
上文介绍了如何对微调后的模型进行使用与简单评估。本文将介绍对微调后的模型进行导出的过程。 一、llama-3微调后的模型导出 首先进入虚拟环境,打开LLaMA-Factory的webui页面 conda activate GLM cd LLaMA-Factory llamafactory-cli webui 之后,选择…...

动态路由协议 —— EIGRP 与 OSPF 的区别
EIGRP(增强内部网关路由协议)和 OSPF(开放式最短路径优先)是两种最常见的动态路由协议,主要是用来指定路由器或交换机之间如何通信。将其应用于不同的情况下,可提高速率、延迟等方面的性能。那么它们之间到…...

【中项】系统集成项目管理工程师-第5章 软件工程-5.1软件工程定义与5.2软件需求
前言:系统集成项目管理工程师专业,现分享一些教材知识点。觉得文章还不错的喜欢点赞收藏的同时帮忙点点关注。 软考同样是国家人社部和工信部组织的国家级考试,全称为“全国计算机与软件专业技术资格(水平)考试”&…...

HarmonyOS应用开发者高级认证,Next版本发布后最新题库 - 多选题序号1
基础认证题库请移步:HarmonyOS应用开发者基础认证题库 注:有读者反馈,题库的代码块比较多,打开文章时会卡死。所以笔者将题库拆分,单选题20个为一组,多选题10个为一组,题库目录如下,…...

Windows11(24H2)LTSC长期版下载!提前曝光Build26100?
系统;windows11 文章目录 前言一、LTSC是什么?二、 Windows 11 Vision 24H2 LTSC 的版本号为 Build 26100,镜像中提供以下三个 SKU:总结 前言 好的系统也能给你带来不一样的效果。 一、LTSC是什么? & & L…...

【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第三篇 嵌入式Linux驱动开发篇-第四十三章 驱动模块传参
i.MX8MM处理器采用了先进的14LPCFinFET工艺,提供更快的速度和更高的电源效率;四核Cortex-A53,单核Cortex-M4,多达五个内核 ,主频高达1.8GHz,2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…...

uniapp 小程序 支付逻辑处理
uniapp 小程序 支付逻辑处理 上代码如果你不需要支付宝适配,可以删除掉支付宝的条件判断代码 <button class"subBtn" :disabled"submiting" click"goPay">去支付</button>// 以下代码你需要改的地方// 1. order/app/v1…...

scikit-learn库学习之make_regression函数
scikit-learn库学习之make_regression函数 一、简介 make_regression是scikit-learn库中用于生成回归问题数据集的函数。它主要用于创建合成的回归数据集,以便在算法的开发和测试中使用。 二、语法和参数 sklearn.datasets.make_regression(n_samples100, n_feat…...

经典文献阅读之--World Models for Autonomous Driving(自动驾驶的世界模型:综述)
Tip: 如果你在进行深度学习、自动驾驶、模型推理、微调或AI绘画出图等任务,并且需要GPU资源,可以考虑使用UCloud云计算旗下的Compshare的GPU算力云平台。他们提供高性价比的4090 GPU,按时收费每卡2.6元,月卡只需要1.7元每小时&…...

孙健提到的实验室的研究方向之一是什么?()
孙健提到的实验室的研究方向之一是什么?() 点击查看答案 A.虚拟现实B.环境感知和理解 C.智能体博弈D.所有选项都正确 图灵奖是在哪一年设立的?() A.1962B.1966 C.1976D.1986 孙健代表的实验室的前身主要研究什么?&…...

初级java每日一道面试题-2024年7月23日-Iterator和ListIterator有什么区别?
面试官: Iterator和ListIterator有什么区别? 我回答: Iterator和ListIterator都是Java集合框架中用于遍历集合元素的接口,但它们之间存在一些关键的区别,主要体现在功能和使用场景上。下面我将详细解释这两种迭代器的不同之处: 1. Iterat…...