设计模式学习(十):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工厂模式

相关内容

热门资讯

安卓系统app和ios系统的区... 你有没有发现,手机里的APP就像是个大杂烩,各有各的特色,各有各的玩法。今天,咱们就来聊聊安卓系统和...
宿迁综合办公系统安卓,便捷高效... 你有没有听说最近宿迁市推出了一款超级方便的安卓应用——宿迁综合办公系统?这可是个大新闻,让我来给你详...
小米平板4系统安卓下载,畅享智... 亲爱的数码爱好者们,你是否在寻找一款性价比超高、性能稳定的平板电脑呢?小米平板4绝对是你的不二之选!...
安卓系统易用性盘点,人性化设计... 你有没有发现,手机里的安卓系统就像一个万能的小助手,无论你是喜欢玩游戏、看视频,还是处理工作,它都能...
鸿蒙系统中出现安卓代码 鸿蒙系统中的安卓代码奇缘在当今科技飞速发展的时代,智能手机已经成为了我们生活中不可或缺的一部分。而在...
安卓系统的双开免费的,免费畅享... 《探索安卓系统的双开免费新世界》在数字化时代,智能手机已经成为我们生活中不可或缺的一部分。而在这众多...
转国外的安卓系统,探索国外安卓... 你有没有想过,让你的安卓手机体验一下国外的风味呢?想象那些国外的应用、游戏,还有那独特的系统设置,是...
安卓系统韩国能用吗,兼容性与使... 你有没有想过,如果你去韩国旅游或者工作,你的安卓手机还能不能用呢?这个问题可真是让人好奇啊!毕竟,每...
安卓手机系统占多少储存 你有没有发现,你的安卓手机越来越慢了?是不是觉得存储空间不够用,连个新应用都装不下?别急,今天就来给...
freemeos是安卓系统吗,... 你有没有听说过freemeOS这个系统?是不是好奇它是不是安卓系统呢?今天,我就来给你揭秘这个神秘的...
安卓系统其他应用耗电大,那些默... 手机电量总是不够用?是不是觉得安卓系统的其他应用耗电特别大?别急,今天就来给你揭秘这个谜团,让你手机...
华为os系统怎么换安卓系统,轻... 你有没有想过,你的华为手机里那个自家的OS系统,突然间想换换口味,试试安卓的精彩世界呢?别急,今天就...
诺基亚回用安卓系统吗,新篇章的... 你有没有听说最近的大消息?诺基亚,那个曾经手机界的巨头,竟然有可能会重新启用安卓系统!这可不是开玩笑...
安卓软件开发考勤系统 你有没有想过,在忙碌的安卓软件开发工作中,如何轻松管理团队考勤呢?别急,今天就来给你揭秘一款特别实用...
炉石传说安卓系统要求,解锁全新... 亲爱的玩家们,你是否已经迫不及待地想要在安卓设备上畅玩《炉石传说》了呢?别急,在这之前,你得先确保你...
安卓手机刷掌阅系统 你有没有想过,你的安卓手机可以变成一个掌阅小能手呢?没错,就是那种随时随地都能畅读各种电子书的掌阅系...
飞车手游ios系统跟安卓系统,... 你有没有发现,最近手机上的一款飞车手游特别火呢?这款游戏不仅画面精美,操作流畅,而且玩法多样,吸引了...
安卓平板显示系统不兼容,安卓平... 你有没有遇到过这种情况?买了一款心仪的安卓平板,满怀期待地想要体验各种精彩应用,结果却发现有些应用显...
安卓系统安装破解app病毒,安... 你知道吗?在安卓系统上安装破解版的APP,听起来是不是有点刺激?但别高兴得太早,这背后可是隐藏着不少...
安卓版桌面操作系统,探索安卓桌... 你有没有想过,你的安卓手机桌面操作系统,其实就像是一个小小的魔法世界呢?在这个世界里,你可以随意布置...