Iterator设计模式
目录
1、示例
1.1 Aggregate接口
1.2 Iterator接口
1.3 Book类
1.4 BookShelf类
1.6 BookShelfIterator 类
1.7 Main类
2、解释Iterator模式中的角色
2.1 Iterator模式的存在意义
2.2 抽象类和接口
2.3 Aggregate 和 Iterator的对应
2.4 容易弄错"下一个"
2.5 容易弄错"最后一个"
2.6 多个Iterator
2.7 多样的迭代器
2.8 不需要deleteIterator
3、相关设计模式
Iterator模式用于在数据集合中按照顺序遍历集合,不需要知道集合对象的底层表示。
1、示例
将书(Book)放置在书架(BookShelf)中,并将书中的名字按顺序显示出来。
示例程序的类图:
类和接口的说明:
名字 | 说明 |
Aggregate | 表示集合的接口 |
Iterator | 遍历集合的接口 |
Book | 表示书的类 |
BookShelf | 表示书架的类 |
BookShelfIterator | 遍历书架的类 |
Main | 测试程序行为的类 |
1.1 Aggregate接口
Aggregate接口是所要遍历的集合的接口。实现了该接口的类将成为一个可以保存多个元素的集合,就像数组一样。Aggregate有“使聚集”“集合”的意思。
public interface Aggregate {public abstract Iterator iterator();
}
在Aggregate接口中声明的方法只有一个 -- Iterator
方法。该方法会生成一个用于遍历集合的迭代器。
想要遍历集合中的元素时,可以调用Iterator方法来生成一个实现了Iterator接口的类的实例。
1.2 Iterator接口
Ite接口用于遍历集合中的元素,其作用相当于循环语句中的循环变量。定义方式有很多种,这里编写最简单的Iterator接口。
public interface Iterator {public abstract boolean hasNext(); //接口中的方法默认抽象,可去掉 abstractpublic abstract Object next();
}
这里我们声明了两个方法,即判断是否存在下-一个元素的hasNext方法,和获取下一个元素的next方法。hasNext方法的返回值是boolean类型的,其原因很容易理解。当集合中存在下一个元素时,该方法返回true;当集合中不存在下一个元素,即已经遍历至集合末尾时,该方法返回false。hasNext方法主要用于循环终止条件。
这里有必要说明一下next方法。该方法的返回类型是object,这表明该方法返回的是集合中的-一个元素。但是,next方法的作用并非仅仅如此。为了能够在下次调用nexxt方法时正确地返回下一个元素,该方法中还隐含着将迭代器移动至下一个元素的处理。说“隐含”,是因为Iterator接口只知道方法名。想要知道next方法中到底进行了什么样的处理,还需要看一下实现了Iterator接口的类( BookShelfIterator)。这样,我们才能看懂next方法的作用。
1.3 Book类
Book类是表示书的类。这个类的作用有限,可以做的事情只有一件 -- 通过 getName 方法获取书的名字。书的名字是在外部调用Book类的构造函数并初始化Book类时,作为参数传递给Book类的。
public class Book {private String name;public Book(String name) {this.name = name;}public String getName() {return name;}
}
1.4 BookShelf类
BookShelf类是表示书架的类。由于需要将该类作为集合进行处理,因此它实现了Aggregate接口。代码中的implements Aggregate 部分即表示这一点。此外,请注意在BookShelf类中还实现了Aggregate接口的iterator方法。
public class BookShelf implements Aggregate{private Book[] books;private int last = 0;public BookShelf(int maxsize) {this.books = new ArrayList<>(maxsize);}public Book getBookAt(int index) {return books[index];}public void appendBook(Book book) {this.books[last++] = book;}public int getLength() {return last;}@Overridepublic Iterator iterator() {return new BookShelfIterator(this);}
}
这个书架中定义了books字段,它是Book类型的数组。该数组的大小(maxsize)在生成BookShelf的实例时就被指定了。之所以将books字段的可见性设置为private,是为了防止外部不小心改变了该字段的值。
接下来我们看看iterator方法。该方法会生成并返回BookShelfIterator类的实例作为BookShelf类对应的Iterator。当外部想要遍历书架时,就会调用这个方法。
1.6 BookShelfIterator 类
public class BookShelfIterator implements Iterator{private BookShelf bookshelf;private int index;public BookShelfIterator(BookShelf bookshelf) {this.bookshelf = bookshelf;this.index = 0;}@Overridepublic boolean hasNext() {if(index < bookshelf.getLength()) {return true;} else {return false;}}@Overridepublic Object next() {return bookshelf.getBookAt(index++);}
}
因为BookShelfIterator类需要发挥Iterator的作用,所以它实现了Iterator接口。
bookShelf字段表示BookShelfIterator所要遍历的书架。index字段表示迭代器当前所指向的书的下标。
构造函数会将接收到的BookShelf的实例保存在bookShelf字段中,并将index初始化为0。hasNext方法是Iterator接口中所声明的方法。该方法将会判断书架中还有没有下一本书,如果有就返回true,如果没有就返回false。而要知道书架中有没有下一-本书,可以通过比较index和书架中书的总册数( bookShelf . getLength()的返回值)来判断。next方法会返回迭代器当前所指向的书( Book的实例),并让迭代器指向下- -本书。它也是;Iterator接口中所声明的方法。next方法稍微有些复杂,它首先取出book变量作为返回值,然后让index指向后面一-本 书。如果与本章开头的for语句来对比,这里的“让index指向后面一本书”的处理相当于其中的i++,它让循环变量指向下一个元素。
1.7 Main类
使用Main类制作一个小书架。
public class Main {public static void main(String[] args) {BookShelf bookShelf = new BookShelf(4);bookShelf.appendBook(new Book("Around the World in 80 Days"));bookShelf.appendBook(new Book("Bible"));bookShelf.appendBook(new Book("Cinderella"));bookShelf.appendBook(new Book("Daddy-Long-Legs"));Iterator it = bookShelf.iterator();while(it.hasNext()) {Book book = (Book) it.next();System.out.println(book.getName());}}
}
通过bookShelf.iterator()得到的it是用于遍历书架的Iterator实例。while 部分的条件当然就是it .hasNext()了。只要书架上有书,while循环就不会停止。然后,程序会通过it.next()一本一本地遍历书架中的书。
运行结果:
Around the World in 80 Days
Bible
Cinderella
Daddy-Long-Legs进程已结束,退出代码0
2、解释Iterator模式中的角色
读完示例程序,让我们来看看Iterator模式中的登场角色。
- Iterator (迭代器)
-
- 该角色负责定义按顺序逐个遍历元素的接口( API)。在示例程序中,由Iterator接口扮演这个角色,它定义了hasNext和next两个方法。其中,hasNext方法用于判断是否存在下一个元素,next方法则用于获取该元素。
- Concretelterator (具体的迭代器)
-
- 该角色负责实现Iterator角色所定义的接口( API)。在示例程序中,由BookShelfIterator类扮演这个角色。该角色中包含了遍历集合所必需的信息。在示例程序中,BookShelf类的实例保存在bookShelf字段中,被指向的书的下标保存在index字段中。.
- Aggregate (集合)
-
- 该角色负责定义创建Iterator角色的接口( API)。这个接口(API)是-一个方法,会创建出“按顺序访问保存在我内部元素的人”。在示例程序中,由Aggregate接口扮演这个角色,它里面定义了iterator方法。
- ConcreteAggregate (具体的集合)
-
- 该角色负责实现Aggregate角色所定义的接口(API)。它会创建出具体的Iterator角色,即Concretelterator角色。在示例程序中,由BookShelf类扮演这个角色,它实现了iterator 方法。
Iterator模式的类图:
2.1 Iterator模式的存在意义
为什么一定要考虑引入Iterator这种复杂的设计模式呢?如果是数组,直接使用for循环语句进行遍历处理不就可以了吗?为什么要在集合之外引人Iterator这个角色呢?一个重要的理由是,引人Iterator后可以将遍历与实现分离开来。请看下面的代码。
while (it .hasNext()) {Book book = (Book) it.next() ;System. out . println (book . getName());
}
这里只使用了Iterator的hasNext方法和next方法,并没有调用BookShelf的方法。也就是说,这里的while循环并不依赖于BookShelf的实现。
如果编写BookShelf的开发人员决定放弃用数组来管理书本,而是用java. util. Vector取而代之,会怎样呢?不管BookShelf如何变化,只要BookShelf的iterator方法能正确地返回Iterator的实例(也就是说,返回的Iterator类的实例没有问题,hasNext和next方法都可以正常工作),即使不对上面的while循环做任何修改,代码都可以正常工作。
这对于BookShelf的调用者来说真是太方便了。设计模式的作用就是帮助我们编写可复用的类。所谓“可复用”,就是指将类实现为“组件”, 当一个组件发生改变时,不需要对其他的组件进行修改或是只需要很小的修改即可应对。这样也就能理解为什么在示例程序中iterator方法的返回值不是BookShelfIterator类型而是Iterator类型了(代码清单1-6)。这表明,这段程序就是要使用Iterator的方法进行编程,而不是BookShelfIterator的方法。
2.2 抽象类和接口
难以理解抽象类和接口的人常常使用ConcreteAggregate角色和ConcreteIterator角色编程,而
不使用Aggregate接口和Iterator接口,他们总想用具体的类来解决所有的问题。
但是如果只使用具体的类来解决问题,很容易导致类之间的强耦合,这些类也难以作为组件被
再次利用。为了弱化类之间的耦合,进而使得类更加容易作为组件被再次利用,我们需要引入抽象
类和接口。
“不要只使用具体类来编程,要优先使用抽象类和接口来编程”需印在脑海中。
2.3 Aggregate 和 Iterator的对应
仔细回忆一下我们是如何把BookShelfIterator类定义为BookShelf类的ConcretelIterator角色的。BookShelfIterator 类知道BookShelf是如何实现的。也正是因为如此,我们才能调用用来获取下一本书的getBookAt方法。
也就是说,如果BookShelf的实现发生了改变,即getBookAt方法这个接口( API)发生变化时,我们必须修改BookShelfIterator类。正如Aggregate和Iterator这两个接口是对应的一样,ConcreteIterator这两个类也是对应的。
2.4 容易弄错"下一个"
在Iterator模式的实现中,很容易在next方法上出错。该方法的返回值到底是应该指向当前元素还是当前元素的下一个元素呢?更详细地讲,next方法的名字应该是下面这样的。
return CurrentElementAndAdvanceToNextPosition
也就是说,next方法是“返回当前的元素,并指向下一个元素”。
2.5 容易弄错"最后一个"
在Iterator模式中,不仅容易弄错“下一个”,还容易弄错“最后一个”。 hasNext方法在返回最后一个元素前会返回true,当返回了最后一个元素后则返回false。稍不注意,就会无法正确地返回“最后一个”元素。
请大家将hasNext方法理解成“确认接下来是否可以调用next方法”的方法就可以了。
2.6 多个Iterator
“将遍历功能置于Aggregate角色之外”是Iterator模式的一个特征。根据这个特征,可以针对一个ConcreteAggregate角色编写多个ConcreteIterator角色。
2.7 多样的迭代器
在示例程序中展示的Iterator类只是很简单地从前向后遍历集合。其实,遍历的方法是多种多样的。
- 从最后开始向前遍历
- 既可以从前向后遍历,也可以从后向前遍历(既有next方法也有previous方法)
- 指定下标进行“跳跃式”遍历
学到这里,相信大家应该可以根据需求编写出各种各样的Iterator类了。
2.8 不需要deleteIterator
在Java中,没有被使用的对象实例将会自动被删除(垃圾回收, GC)。因此,在iterator中不需要与其对应的deleteIterator方法。
3、相关设计模式
- Visitor 模式
-
- Iterator模式是从集合中-一个-一个取出元素进行遍历,但是并没有在Iterator接口中声明对取出的元素进行何种处理。
-
- Visitor模式则是在遍历元素集合的过程中,对元素进行相同的处理。在遍历集合的过程中对元素进行固定的处理是常有的需求。Visitor 模式正是为了应对这种需求而出现的。在访问元素集合的过程中对元素进行相同的处理,这种模式就是Visitor模式。
- Composite模式
-
- Composite模式是具有递归结构的模式,在其中使用Iterator 模式比较困难。
- Factory Method模式
-
- 在iterator方法中生成Iterator的实例时可能会使用Factory Method模式。
相关文章:
Iterator设计模式
目录 1、示例 1.1 Aggregate接口 1.2 Iterator接口 1.3 Book类 1.4 BookShelf类 1.6 BookShelfIterator 类 1.7 Main类 2、解释Iterator模式中的角色 2.1 Iterator模式的存在意义 2.2 抽象类和接口 2.3 Aggregate 和 Iterator的对应 2.4 容易弄错"下一个"…...
ROS 入门
目录 简介 ROS诞生背景 ROS的设计目标 ROS与ROS2 安装ROS 1.配置ubuntu的软件和更新 2.设置安装源 3.设置key 4.安装 5.配置环境变量 安装可能出现的问题 安装构建依赖 卸载 ROS架构 1.设计者 2.维护者 3. 立足系统架构: ROS 可以划分为三层 ROS通信机制 话…...
第四章 Linux网络编程
ARP 协议 ARP 协议(Address Resolution Protocol)通过 IP 地址查找对应的 MAC 地址。 当一个主机需要发送数据给另一个主机时,它首先会检查本地的 ARP 缓存表(ARP cache)中是否存在目标主机的 MAC 地址。如果存在&…...
无涯教程-JavaScript - OFFSET函数
描述 OFFSET函数返回对范围的引用,该范围是一个单元格或单元格范围中指定的行数和列数。 返回的引用可以是单个单元格或单元格范围。您可以指定要返回的行数和列数。 语法 OFFSET (reference, rows, cols, [height], [width]) 争论 Argument描述Required/OptionalReferenc…...
rust切片
切片类型写为[T]。 切片是序列的一个片段。 它是动态大小类型,所以要使用切片类型,就必须使用它的指针类型。引用是最常用的指针类型。 [T; n]能隐式转换成[T]。 一、定义切片 (一)不可变切片 &[T],共享切片&…...
2023/9/18 -- C++/QT
作业 完善登录框 点击登录按钮后,判断账号(admin)和密码(123456)是否一致,如果匹配失败,则弹出错误对话框,文本内容“账号密码不匹配,是否重新登录”,给定两…...
vue柱状图+折线图组合
<template><div id"main" style"width: 100%;height: 500px; padding-top: .6rem"></div> </template>data() {return {weekData: ["1周","2周","3周","4周","5周","6周&…...
js中如何实现一个简单的防抖函数?
聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 防抖函数⭐ 使用示例⭐ 写在最后 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅!这个专栏是为那些对Web开发感兴趣、刚刚踏…...
mysq 主从同步错误之 Error_code 1032 handler error HA_ERR_KEY_NOT_FOUND
错误说明: MySQL主从同步的1032错误,一般是指要更改的数据不存在,SQL_THREAD提取的日志无法应用故报错,造成同步失败 (Update、Delete、Insert一条已经delete的数据)。 1032的错误本身对数据一致性没什么影…...
蓝桥杯 题库 简单 每日十题 day4
01 津津上初中了。妈妈认为津津应该更加用功学习,所以津津除了上学之外,还要参加妈妈为她报名的各科复习班。另外每周妈妈还会送她去学习朗诵、舞蹈和钢琴。但是津津如果一天上课超过八个小时就会不高兴,而且上得越久就会越不高兴。假设津津…...
l8-d21 域名解析与http服务器实现原理
一、域名解析gethostbyname函数 主机结构在 <netdb.h> 中定义如下: struct hostent { char *h_name; /* 官方域名 */ char **h_aliases; /* 别名*/ int h_addrtype; /* 地址族(地址类型) */ int h_l…...
网络安全(黑客技术)自学规划
一、什么是网络安全 网络安全可以基于攻击和防御视角来分类,我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术,而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 无论网络、Web、移动、桌面、云等哪个领域,都有攻与防两面性…...
阻止用邮件不停注册wordpress账户的方法
您可以使用多种不同的策略来阻止垃圾邮件注册。以下是一些策略供您参考:第1个最好用 1.完全禁用WordPress注册:如果您不需要在您的WordPress网站上公开注册,最好完全禁用注册,而不是试图打击垃圾邮件注册。要完全禁用WordPress上…...
低代码工具大比拼:哪个最适合你?
低代码开发平台正日益流行,成为企业和开发者们的首选。但是,面对市场上众多的低代码工具,你是否感到困惑呢?今天,就和数聚股份一起探讨一下,究竟应该选择哪个低代码工具才能最好地满足你的需求。 首先&…...
用Python实现链式调用
嗨喽,大家好呀~这里是爱看美女的茜茜呐 我们在使用Django的models查询数据库时,可以看到有这种写法: form app.models import XXX query XXX.objects.all() query query.filter(name123, age456).filter(salary999)在这种写法里面…...
基于SSM的汽车租赁后台管理系统
基于SSM的汽车租赁后台管理系统 介绍 包括登录、首页、客户管理、车辆管理、汽车出租、出租单管理、汽车入库、检查单管理、系统管理等功能,适合二次开发课程设计、毕业设计等 软件架构 SSM 运行环境 数据库 mysql 安装教程输入链接说明 端口:3306…...
Word 文档转换 PDF、图片
工作有需要 Word 文档转换 PDF、图片 的场景,我们来看看 Java 开发中怎么解决这个问题的。 Word 转 PDF Word 转 PDF 分为商用 Aspose 方案和开源 Apache POIiText 方案。 Aspose 方案 这种方式在目前来看应该是最好的,无论是转换的速度还是成功的概…...
解决Permission is not allowed后基于Ubuntu23.04安装配置docker与docker-compose
参考:Docker官网-Install Docker Engine on Ubuntu 一、 Install using the Apt repository 1.1 Set up Docker’s Apt repository 1.1.1 Add Docker’s official GPG key # Add Dockers official GPG key: sudo apt-get updatesudo apt-get install ca-certifi…...
[ABC118D] Match Matching
题目传送门 引 题目的描述很形象,梦回童年,注意一下火柴全部都用完 解法 显然 DP , 设计状态: f i : 用完 i 根木棒凑出的最大数 f_i:用完i根木棒凑出的最大数 fi:用完i根木棒凑出的最大数 状态转移: f i → f i c n t …...
程序员必须掌握哪些算法?
目录 简介1. 冒泡排序(Bubble Sort)思想 2. 快速排序(Quick Sort)思想 3. 二分查找(Binary Search)思想 4. 归并排序(Merge Sort)思想 5. 插入排序(Insertion Sort&#…...
Java高级之File类、节点流、缓冲流、转换流、标准I/O流、打印流、数据流
第13章 IO流 文章目录 一、File类的使用1.1、如何创建File类的实例1.2、常用方法1.2.1、File类的获取功能1.2.2、File类的重命名功能1.2.3、File类的判断功能1.2.4、File类的创建功能1.2.5、File类的删除功能 二、IO流原理及流的分类2.1、Java IO原理2.2、流的分类/体系结构 三…...
解决WSL2占用内存过多问题(Docker on WSL2: VmmemWSL)
解决WSL2占用内存过多问题(Docker on WSL2: VmmemWSL) 一、问题描述二、问题解决2.1 创建.wslconfig文件2.2 重启wsl2 一、问题描述 安装完WSL2后,又安装了Docker,使用了一段时间,发现电脑变卡,进一步查看…...
华为云云耀云服务器L实例评测|了解配置和管理L型云服务器
华为云云耀云服务器L实例配置和管理教程 华为云云耀云服务器L实例的介绍概述特点优势与弹性云服务器(ECS)的对比 注册和创建L型云服务器注册华为云账号创建L型云服务器实例配置实例参数配置其他参数尝试登录 远程登录 L实例查看公网ip通过本地shell远程连…...
【面试题】——Java基础篇(33题)
文章目录 1. 八大基本数据类型分类2. 重写和重载的区别3. int和integer区别4. Java的关键字5. 什么是自动装箱和拆箱?6. 什么是Java的多态性?7. 接口和抽象类的区别?8. Java中如何处理异常?9. Java中的final关键字有什么作用&…...
记一次 .NET 某电力系统 内存暴涨分析
一:背景 1. 讲故事 前些天有位朋友找到我,说他生产上的程序有内存暴涨情况,让我帮忙看下怎么回事,最简单粗暴的方法就是让朋友在内存暴涨的时候抓一个dump下来,看一看大概就知道咋回事了。 二:Windbg 分…...
1.SpringEL初始
SpringEL初始 文章目录 SpringEL初始什么是SpringELSpring BeansSpring EL以XML形式Spring EL以注解形式启用自动组件扫描 执行输出 什么是SpringEL Spring EL与OGNL和JSF EL相似,计算评估或在bean创建时执行。此外,所有的Spring表达式都可以通过XML或注…...
HTTP 状态码
状态码状态码英文名称中文描述100Continue继续。客户端应继续其请求101Switching Protocols切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到HTTP的新版本协议200OK请求成功。一般用于GET与POST请求201Created已创建。成功…...
ddtrace 系列篇之 dd-trace-java 项目编译
dd-trace-java 是 Datadog 开源的 java APM 框架,本文主要讲解如何编译 dd-trace-java 项目。 环境准备 JDK 编译环境(三个都要:jdk8\jdk11\jdk17) Gradle 8 Maven 3.9 (需要 15G 以上的存储空间存放依赖) Git >2 (低于会出现一想不到的异常…...
华为aarch64架构的泰山服务器EulerOS 2.0 (SP8)系统离线安装saltstack3003.1实践
华为泰山服务器的CPU芯片架构为aarch64,所装系统为EulerOS 2.0 (SP8)aarch64系统,安装saltstack比较困难。本文讲解通过pip安装方式离线安装saltstack3003.1以进行集中化管理和维护。 一、系统环境 1、操作系统版本 [rootlocalhost ~]# cat /etc/os-r…...
C#中的方法
引言 在C#编程语言中,方法是一种封装了一系列可执行代码的重要构建块。通过方法,我们可以将代码逻辑进行模块化和复用,提高代码的可读性和可维护性。本文将深入探讨C#中的方法的定义、参数传递、返回值、重载、递归等方面的知识,…...
网站备案密码通管局/seo博客网站
大规模用户运营体系有3大子系统,分别是:用户生命周期管理系统、用户分层运营系统、用户行为激励系统。今天我们聊的正是用户运营体系其中的一个子系统—用户生命周期管理系统。从本质上讲,用户生命周期管理的最终目的是为了提升用户价值。 什…...
网站推广适合女生做吗/网络营销模式案例
sprintf函数的unicode版本_stprintf 其他的如strcat等,建议使用_tcscat, _tcscpy, _tcscmp、_tcsncmp、_tcslen等等。 sprintf()函数的用法总结...
网站怎么做数据备份/广州网站建设方案维护
通过Web.config实现301重定向 IIS7以上可以通过修改Web.config实现IIS设置 现在我们通过Web.config实现301重定向 <system.webServer><validation validateIntegratedModeConfiguration"false" /><modules runAllManagedModulesForAllRequests"t…...
南昌网站建设哪家好薇/专业的seo外包公司
Problem Description自从Lele开发了Rating系统,他的Tetris事业更是如虎添翼,不久他遍把这个游戏推向了全球。为了更好的符合那些爱好者的喜好,Lele又想了一个新点子:他将制作一个全球Tetris高手排行榜,定时更新&#x…...
义乌网站优化/苏州seo关键词优化软件
今天在改进文件监视程序时写的框架代码,监视文件修改(采用完成端口和ReadDirectoryChangesW同时在一个线程中监视多个目录,并且能够判断文件是否完全复制完毕) #define STRICT #define WINVER 0x0500 #define _WIN32_WINNT 0x0500 #define…...
织梦网站专题页面如何做/深圳市seo点击排名软件价格
导语JAVA进程消失可能有哪些原因?那我们就开一篇文章说一下这个问题,其实很easy的,无外乎三种情况。linux的OOM killer杀死JVM自身故障jvm的OOM导致进程退出(很罕见,我至今没遇见过)linux的OOM killerLinux 内核有个机制叫OOM kil…...