设计模式学习(十):lterator迭代器模式
创始人
2024-05-14 13:42:50
0

一、什么是Iterator模式

使用Java语言显示数组arr中的元素时,我们可以使用下面这样的for循环语句遍历数组。

for (int i = 0; i < arr.length; i++){system.out.println(arr[i]);
}

请注意这段代码中的循环变量i。该变量的初始值是o,然后会递增为1,2,3,...,程序则在每次i递增后都输出arr[i]。我们在程序中经常会看到这样的for循环语句。

for语句中的i++的作用是让i的值在每次循环后自增1,这样就可以访问数组中的下一个元素、下下一个元素、再下下一个元素,也就实现了从头至尾逐一遍历数组元素的功能。

将这里的循环变量i的作用抽象化、通用化后形成的模式,在设计模式中称为Iterator模式。lterator模式用于在数据集合中按照顺序遍历集合。英语单词Iterate有反复做某件事情的意思,汉语称为“迭代器”。

用一句话来概括:一个一个遍历

二、Iterator模式示例代码

首先,让我们来看一段实现了Iterator模式的示例程序。这段示例程序的作用是将书(Book)放置到书架(BookShelf)中,并将书的名字按顺序显示出来。

2.1 类之间的关系

类和接口的功能:

类图:

2.2 Aggregate接口

Aggregate接口是所要遍历的集合的接口。实现了该接口的类将成为一个可以保存多个元素的集合,就像数组一样。Aggregate有“使聚集”、“集合”的意思。

public interface Aggregate {public abstract Iterator iterator();
}

2.3 lterator接口

Iterator接口用于遍历集合中的元素,其作用相当于循环语句中的循环变量。

这里有必要说明一下next方法。该方法的返回类型是Object,这表明该方法返回的是集合中的一个元素。但是,next方法的作用并非仅仅如此。为了能够在下次调用next方法时正确地返回下一个元素,该方法中还隐含着将迭代器移动至下一个元素的处理。说“隐含”,是因为Iterator接口只知道方法名。想要知道next方法中到底进行了什么样的处理,还需要看一下实现了Iterator接口的类( BookShelfIterator)。这样,我们才能看懂next方法的作用。

/*** 用于遍历集合中的元素*/
public interface Iterator {/*** 判断是否存在下一个元素* @return 当集合中存在下一个元素时,该方法返回true*         当集合中不存在下一个元素,即已经遍历至集合末尾时,返回false*/public abstract boolean hasNext();/*** 获取下一个元素* @return 下一个元素*/public abstract Object next();
}

2.4 Book类

Book类是表示书的类。

public class Book {//书名private String name;public Book(String name) {this.name = name;}/*** 获取书的名字*/public String getName() {return name;}
}

2.5 BookShelf类

BookShelf类是表示书架的类。由于需要将该类作为集合进行处理,因此它实现了Aggregate接口。此外,请注意在BookShelf类中还实现了Aggregate接口的iterator方法。

之所以将books字段的可见性设置为private,是为了防止外部不小心改变了该字段的值。

接下来我们看看iterator方法。该方法会生成并返回BookShelfIterator类的实例作为BookShelf类对应的Iterator。当外部想要遍历书架时,就会调用这个方法。

public class BookShelf implements Aggregate{//书架上的书。数组大小在构造函数中指定private Book[] books;private int last = 0;public BookShelf(int maxsize) {this.books = new Book[maxsize];}public Book getBookAt(int index) {return books[index];}public void appendBook(Book book) {this.books[last] = book;last++;}public int getLength() {return last;}@Overridepublic Iterator iterator() {return new BookShelfIterator(this);}
}

2.6 BookShelflterator类

用于遍历书架的类。

public class BookShelfIterator implements Iterator {//要遍历的书架private BookShelf bookShelf;//迭代器当前所指向的书的下标private int index;public BookShelfIterator(BookShelf bookShelf) {this.bookShelf = bookShelf;this.index = 0;}/*** 判断书架中还有没有下一本书* @return 如果有就返回true,如果没有就返回false*/@Overridepublic boolean hasNext() {//比较index和书架中书的总册数if (index < bookShelf.getLength()) {return true;} else {return false;}}/*** 返回迭代器当前所指向的书(Book的实例),并让迭代器指向下一本书*/@Overridepublic Object next() {Book book = bookShelf.getBookAt(index);index++;return book;}
}

2.7 Main类

public class Main {public static void main(String[] args) {BookShelf bookShelf = new BookShelf(4);bookShelf.appendBook(new Book("Romance of the Three Kingdoms"));bookShelf.appendBook(new Book("A Dream in Red Mansions"));bookShelf.appendBook(new Book("The Story of Stone"));bookShelf.appendBook(new Book("Journey to the West"));Iterator it = bookShelf.iterator();while (it.hasNext()) {Book book = (Book) it.next();System.out.println(book.getName());}}
}

2.8 运行结果

通过bookShelf.iterator()得到的it是用于遍历书架的Iterator实例。while部分的条件当然就是it.hasNext()了。只要书架上有书,while循环就不会停止。然后,程序会通过it.next()一本—本地遍历书架中的书。

三、拓展思路的要点

3.1 不管实现如何变化,都可以使用lterator

为什么一定要考虑引入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类型了。这表明,这段程序就是要使用Iterator的方法进行编程,而不是BookShelfIterator的方法。

3.2 难以理解抽象类和接口

难以理解抽象类和接口的人常常使用ConcreteAggregate 角色和Concretelterator角色编程,而不使用Aggregate接口和Iterator接口,他们总想用具体的类来解决所有的问题。

但是如果只使用具体的类来解决问题,很容易导致类之间的强耦合,这些类也难以作为组件被再次利用。为了弱化类之间的耦合,进而使得类更加容易作为组件被再次利用,我们需要引入抽象类和接口。

3.3 Aggregate和 Iterator的对应

请大家仔细回忆一下我们是如何把BookShelfIterator类定义为BookShelf类的Concretelterator 角色的。BookShelfIterator类知道BookShelf是如何实现的。也正是因为如此,我们才能调用用来获取下一本书的getBookAt方法。

也就是说,如果BookShelf的实现发生了改变,即getBookAt方法这个接口(API)发生变化时,我们必须修改BookShelfIterator类。

正如Aggregate和Iterator这两个接口是对应的一样,ConcreteAggregate和concreteIterator这两个类也是对应的。

3.4 容易弄错“下一个”

在Iterator模式的实现中,很容易在next方法上出错。该方法的返回值到底是应该指向当前元素还是当前元素的下一个元素呢?更详细地讲,next方法的名字应该是下面这样的。

returnCurrentElementAndAdvanceToNextPosition

也就是说,next方法是“返回当前的元素,并指向下一个元素”。

3.5 还容易弄错“最后一个”

在Iterator模式中,不仅容易弄错“下一个”,还容易弄错“最后一个”。hasNext方法在返回最后一个元素前会返回true,当返回了最后一个元素后则返回false。稍不注意,就会无法正确地返回“最后一个”元素。

请大家将hasNext方法理解成“确认接下来是否可以调用next方法”的方法就可以了。多个lterator

“将遍历功能置于Aggregate角色之外”是Iterator模式的一个特征。根据这个特征,可以针对一个ConcreteAggregate角色编写多个ConcreteIterator角色。

3.6 迭代器的种类多种多样

在示例程序中展示的Iterator类只是很简单地从前向后遍历集合。其实,遍历的方法是多种多样的。

  • 从最后开始向前遍历

  • 既可以从前向后遍历,也可以从后向前遍历(既有next方法也有previous方法)

  • 指定下标进行“跳跃式”遍历

学到这里,相信大家应该可以根据需求编写出各种各样的Iterator类了。

3.7 不需要deletelterator

在Java中,没有被使用的对象实例将会自动被删除(垃圾回收,GC)。因此,在iterator中不需要与其对应的deleteIterator方法。

四、相关的设计模式

4.1 Visitor模式

Iterator模式是从集合中一个一个取出元素进行遍历,但是并没有在Iterator接口中声明对取出的元素进行何种处理。

Visitor模式则是在遍历元素集合的过程中,对元素进行相同的处理。

在遍历集合的过程中对元素进行固定的处理是常有的需求。Visitor模式正是为了应对这种需求而出现的。在访问元素集合的过程中对元素进行相同的处理,这种模式就是Visitor模式。

4.2 Composite模式

Composite模式是具有递归结构的模式,在其中使用Iterator模式比较困难。

4.3 Factory Method模式

在iterator方法中生成Iterator的实例时可能会使用Factory Method模式。

设计模式学习(七):Factory Method工厂模式

相关内容

热门资讯

原生安卓系统怎样升级,从基础到... 你有没有发现,你的安卓手机用久了,有时候就像老牛拉车一样,慢吞吞的?别急,今天就来给你支个招,让你的...
安卓13系统怎么开发,开发者的... 你有没有听说安卓13系统已经发布了?这可是个大新闻呢!作为一个热衷于手机开发的小伙伴,你是不是也跃跃...
安卓q系统镜像下载,轻松升级体... 你有没有听说安卓Q系统已经发布了?这可是安卓家族里的一大亮点呢!今天,我就要来给你详细介绍一下安卓Q...
安卓系统色彩校正软件,打造个性... 你有没有发现,手机屏幕的色彩有时候会让人感觉不太对劲?有时候,画面看起来有点灰蒙蒙的,有时候又太艳丽...
苹果能否下个安卓系统,开启新篇... 你有没有想过,苹果的iOS系统会不会有一天突然宣布,它要拥抱安卓的大家庭呢?想象iPhone和iPa...
树莓派 装 安卓系统,轻松安装... 你有没有想过,用树莓派装上安卓系统,那会是怎样一番景象呢?想象一个迷你电脑,竟然能运行起我们日常使用...
安卓系统怎么打印小票,安卓系统... 你是不是也遇到了这样的烦恼:手机里存了好多重要的小票,但是想打印出来保存或者报销,却发现安卓系统里的...
安卓10安装系统应用,轻松上手... 你有没有发现,你的安卓手机最近是不是有点儿“慢吞吞”的?别急,别急,今天就来给你支个招——升级安卓1...
美国不提安卓系统华为,迈向自主... 华为与美国:一场关于技术、市场与政策的较量在当今这个数字化的世界里,智能手机已经成为我们生活中不可或...
安卓系统怎么打开ppt,选择文... 你有没有遇到过这种情况:手里拿着安卓手机,突然需要打开一个PPT文件,却怎么也找不到方法?别急,今天...
谷歌退回到安卓系统,探索创新未... 你知道吗?最近科技圈可是炸开了锅,谷歌竟然宣布要退回到安卓系统!这可不是一个简单的决定,背后肯定有着...
安卓系统待机耗电多少,深度解析... 你有没有发现,手机电量总是不经用?尤其是安卓系统,有时候明明没怎么用,电量就“嗖”的一下子就下去了。...
小米主题安卓原生系统,安卓原生... 亲爱的手机控们,你是否曾为手机界面单调乏味而烦恼?想要给手机换换“衣服”,让它焕然一新?那就得聊聊小...
voyov1安卓系统,探索创新... 你有没有发现,最近你的手机是不是变得越来越流畅了?没错,我要说的就是那个让手机焕发青春的Vivo V...
电脑刷安卓tv系统,轻松打造智... 你有没有想过,家里的安卓电视突然变得卡顿,反应迟钝,是不是时候给它来个“大保健”了?没错,今天就要来...
安卓系统即将要收费,未来手机应... 你知道吗?最近有个大消息在科技圈里炸开了锅,那就是安卓系统可能要开始收费了!这可不是开玩笑的,这可是...
雷凌车载安卓系统,智能出行新体... 你有没有发现,现在的汽车越来越智能了?这不,我最近就体验了一把雷凌车载安卓系统的魅力。它就像一个聪明...
怎样拍照好看安卓系统,轻松拍出... 拍照好看,安卓系统也能轻松搞定!在这个看脸的时代,拍照已经成为每个人生活中不可或缺的一部分。无论是记...
安卓车机系统音频,安卓车机系统... 你有没有发现,现在越来越多的汽车都开始搭载智能车机系统了?这不,咱们就来聊聊安卓车机系统在音频方面的...
老苹果手机安卓系统,兼容与创新... 你手里那台老苹果手机,是不是已经陪你走过了不少风风雨雨?现在,它竟然还能装上安卓系统?这可不是天方夜...