关于迭代器(Iterator)
迭代器这个名词想来我们已经不陌生了,在集合中我们就学习过迭代器,并掌握了如何使用迭代器来遍历集合中的元素。
1 | 例如: |
实际上,迭代器就是反复同一件事的一个循环,就如同for(int i = 0; i < 100; i++)中的i++,只要符合条件就加1,直到遍历完每一个元素后就退出,而迭代器模式(Iterator模式)的思想也就是来自于此。迭代器模式是一种没落的模式,除非产品性质的需要,否则不会单独去写一个迭代器模式(Java中的集合就对迭代器模式进行优秀的封装,基本上不用认为扩展,都能满足我们的需求)。我们可以看看迭代器的定义:迭代器提供一种方法访问一个容器对象中各个元素,而又不暴露该对象的细节。通俗点说,迭代器的诞生就是为遍历容器(容器就是能持有对象的集合,如Collection,Set)中的元素服务的。
迭代器模式——你在不在?我要揍你一顿
举一个例子,详细讲讲什么是迭代器模式
在一个风和日丽的早晨,阳光明媚,春暖花开,打开古老的藏书阁,我要找一本心仪的古书陶冶一下情操,可是让我很郁闷的是,由于时间太久没人整理,很多书都凌乱的放在书架上,所以我费了老大的劲儿才把书籍找到。我就在想,要是有一个这样的物件就好了,它能在我想要从一堆杂乱无章的事物中寻找某一件东西时,它能按整齐的把它排列(排列顺序自己选择)好,这样我找的时候不就容易多了,我冥思苦想很久,找了很多上古典籍查阅(《设计模式之禅》,《图解设计模式》)中找到了答案,那就是上古秘书——迭代器模式。
现有一个书架BookShelf,有一堆书Book,我想把书放到书架上,并按照书的名字按顺序显示出来。看一下示例图
程序的类图如下
类和接口
逐步剖析(请直接看代码)
Aggregate接口:表示集合的接口,相当于Java集合中Collection,List等集合接口1
2
3
4
5
6
7
8
9
10
11
12
13
14/**
* 表示集合的接口
*/
public interface Aggregate {
/**
* 该方法用于生成一个遍历结合的迭代器
*
* 在遍历集合中的元素时吗,调用iterator方法生成一个实现了Iterator接口的类的实例
* @return
*/
public abstract Iterator iterator();
}
Iterator接口:表示用于遍历集合的接口
1 | /** |
BookShelf类:实现了Aggregate接口,表示一个书籍的集合,可以看成Java集合框架中的实现类
1 | /** |
BookShelfIterator类:Iterator的实现类
1 | /** |
Book类:书籍类(实体类)
1 | public class Book { |
下面是Main方法
1 | public class Main { |
集合框架中的迭代器模式(源码解析)
上面是我们自己写的迭代器模式,用我们自己的想法实现了一个简单的迭代器,怎么样,你对迭代器了解有多少了呢,如果你还是不清楚,那我们再来看看Java集合框架是如何运用迭代器的。我将主要以源码的方式解析,你会发现其实和我上面写的差不多。
1 | 我就使用List接口进行解析,List定义了如下方法 |
深入研究一下
OK,上面就是迭代器在集合框架中的使用,现在我们或许就理解了为什么在学习集合的迭代器器时说,我们是去获取一个迭代器,而并非是我们new一个迭代器对象,下面我们来看看迭代器模式的类图,并分析一下我们为什么要使用迭代器
- Iterator(迭代器):该角色定义了顺序逐个遍历元素的接口
- ConcreteIterator(具体的迭代器):实现Iterator接口
- Aggregate(集合):定义创建Iterator角色的接口
- ConcreteAggregate(具体的集合):该角色负责实现Aggregate所定义的接口
看了上面介绍的迭代器模式,我们或许头有点晕,既然同是迭代,为什么我们不去使用更为普通的迭代方式,如for循环呢,非要用这种复杂的设计模式干什么,其实回到前面迭代器模式的定义:迭代器模式提供一种顺序访问一个聚合对象中各个元素的方法,而又不暴露该对象的内部实现。
举个例子:我是车站的售票员,对于我来说,我只是负责售票的,其他的事情我一概不管,对于我来说,只有一个原则,那就是只有买了票才能乘车,不管你是中国人外国人,不管你是小偷还是杀人犯,只要你没买票就不能乘车,我不用管乘车对象是什么,我只管你有没有买票。
如同上面举的那个例子,这里只是用了Iterator的hasNext和next方法,并没有调用BookShelf的方法,也就是说,while循环并不依赖于BookShelf的实现。不管BookShelf如何变化,只要BookShelf的iterator方法能返回正确的Iterator实例,即使不对while循环做任何修改,都可以正常工作。设计模式的作用就是帮助我们编写可复用的类。而可复用的含义就是将类视为“组件”,当一个组件方法发生变化时,不需要对其他组件进行修改或者只需要进行很小的修改就可以了,大大提高了代码的重用率。
1 | while(iterator.hasNext()){ |
结语
迭代器模式是一种古老的设计模式,也是一种非常常见的设计模式,它已经完美的镶嵌于聚合关系中,如Java的集合框架,几乎每一个集合类都对迭代器模式进行了封装。正是由于它的普遍性,所以很多大佬都提出将迭代器模式从23中设计模式中删除。不管迭代器模式在未来是否还能存在于设计模式家族中,我们只需要知道,应用之广泛则证明其价值,所以值得我们去学习研究它的思想精髓。
推荐书籍与网站:
- 《图解设计模式》 《大话设计模式》 《设计模式》 《Java设计模式》