20.1 乘车买票,不管你是谁?
- 时间: 5月26日10点 地点: 一公交车上 人物:大鸟,小菜
这天是周末, 小菜和大鸟一早出门玩儿, 上了公交, 车内很挤.
“上车的乘客请买票.” 售票员一边在人缝中穿插着, 一边说道.
……
20.2 迭代器模式
“小菜, 今天你真的见到强人了吧.” 大鸟下车后, 对小菜说道.
“这个售票员, 是在够强,” 小菜学者模仿到, “想走,可以.先买票再说.”
“这售票员其实在做一件很重要的事情, 就是把车厢内所有的人都遍历一遍, 不放过每一个买票的乘客. 这也是一个设计模式的体现.”
“大鸟, 你也够强, 什么都可以往设计模式上套, 这也是模式?”
“当然是模式. 这个模式就叫迭代器模式.”
迭代器模式(Iterator), 提供一种顺序访问一个聚合对象中各个元素, 而又不暴露该对象的内部表示.[DP]
“你想呀, 售票员才不过你上来的是物(行李), 不管是中国人还是外国人, 不管是不是内部员工, 甚至哪怕是马上要被抓走的小偷, 只要是来乘车的乘客, 就必须买票. 同样道理, 当你需要访问一个聚集对象, 而且不管这些对象是什么都需要遍历的时候, 你就应该考虑用迭代器模式. 另外, 售票员从车头到车尾来售票, 也可以从车尾到车头来售票, 也就是说, 你需要对聚集有多种遍历时, 可以考虑使用迭代器模式. 由于不管乘客干了什么, 售票员的做法始终是相同的, 都是从第一个开始, 下一个是谁, 是否结束, 当前售到那个人了, 这些方法每天他都在做, 也就是说, 为了遍历不同的聚集结构提供如, 开始, 下一个, 是否结束, 当前项是哪一个的接口.“
“听你这么一说, 好像这个模式也不简单”
“哈, 本来这个模式还有点意思, 不过现今看来, 迭代器模式的实用价值远不如学习价值大了, MartinFlower 甚至在自己的网站上提出撤销此模式. 因为现在高级编程语言如 C#, Java, 等本身已经把这个模式做在语言中了.”
“哦, 是什么?”
“哈, foreach 你熟悉吧?”
“啊, 原来是它, 没错没错, 他就是不需要知道集合对象是什么, 就可以遍历所有的对象的循环工具, 非常好用.”
另外还有 Iterable 接口也是为了迭代器模式而准备的. 不管如何, 学习一下 GoF 的迭代器模式的基本结构, 还是很有学习价值的.
20.3 迭代器模式
Iterator 迭代器抽象类
Aggregate 抽象类
ConcreteIterator 具体迭代器类, 继承Iterator
ConcreteAggregate 具体聚集类, 继承 Aggregate
客户端代码
运行结果
“看到没有, 这就是我们的优秀售票员售票—迭代器模式的整个运作模式.”
“大鸟, 你说为什么要用具体的迭代器 ConcreteIterator 来实现抽象的 Iterator 呢? 我觉得这里不需要抽象啊, 直接访问 ConcreteIterator 不是更好吗?”
“哈, 你是因为刚才有一个迭代器的好处你没注意, 当你需要对聚集有多种方式遍历时, 可以考虑使用迭代器模式, 实际上, 售票员一定要从车头到车尾这样售票吗?”
“你意思是, 他还可以从后向前遍历?”
“当然是可以的, 你不妨再写一个实现从后往前具体迭代器类看看.”
“好的.”
“写的不错, 这是你的客户端只要修改一个地方就可以实现反向遍历了.”
“是呀, 其实售票员完全可以更多的方式来遍历乘客, 比如从最高到最矮, 从最小到最老, 从最靓丽酷比到最猥琐龌龊.” 小菜已经开始头脑风暴.
“神经病, 你当时你呀.” 大鸟笑骂.
20.4 Java 的迭代器的实现
“刚才我们也说过, 实际使用当中是不需要这么麻烦的, 因为 java 框架已经为你准备好了相关的接口, 你只需要去实现就好.”
Iterator 接口
再来看看我们熟悉的 foreach
“这里用到的 foreach, 编译器其实就是做了下面的工作.”
“原来, foreach 就是这两个接口实现循环遍历啊.”
“是的, 尽管我们不需要显示的引用迭代器, 单系统本身还是通过迭代器来实现遍历的. 总的来说, 迭代器(Iterator) 模式就是分离了集合对象的遍历行为, 抽象出一个迭代器类来负责, 这样即可以做到不暴露集合的内部结构, 又可让外部代码透明的访问集合内部的数据. 迭代器模式在访问数据, 集合, 列表等数据时, 尤其是数据库的操作时, 是非常普遍的应用, 但由于它太普遍了, 所以各种高级语言都对他进行了封装, 所以反而给人感觉他不太常用了.”