迭代器模式从来没有写过,第一次接触迭代器,还是好多年前学C++的STL的时候。当时觉得用迭代器太麻烦了,后来用习惯了觉得真香。
UML类图位置:https://www.processon.com/view/link/60d29bf3e401fd49502afd25
本文代码链接为:https://github.com/shidawuhen/asap/blob/master/controller/design/23iterator.go
1.定义
1.1 迭代器模式
迭代器模式(Iterator):提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示。
UML:
1.2分析
通过UML可以看出,对于集合Aggregate,其遍历能力被拆了出来,由Iterator负责遍历。
大家可能有疑问,可以用for循环解决的问题,为啥要搞得这么复杂呢?
其实主要看集合结构的复杂性,如果是普通的数组,可以不需要Iterator,直接使用for循环即可。如果是复杂的集合呢?对于这个集合需要有多种遍历方案呢?
如对于图结构,有广度优先、深度优先两种遍历方式,都在图集合里实现,是否感觉违背了职责单一原则。
所以对于复杂结构,迭代器有如下优势:
- 这种拆分,使集合和迭代器职责更加单一,符合单一职责原则
- 迭代器结构统一,方便使用,使用者无需知道遍历细节便可遍历集合
- 符合开闭原则,可以按照需求自己开发迭代器,无需改动集合类
- 符合里氏替换原则,可以方便的进行迭代方案的更换
通过UML可发现设计思路:迭代器中需要定义first()、isDone()、currentItem()、next() 四个最基本的方法。待遍历的集合对象通过依赖注入传递到迭代器类中。集合可通过CreateIterator() 方法来创建迭代器。
2.应用场景
迭代器模式一般在library中使用的比较多,毕竟library提供的大多是基础结构。实际业务场景中,很少需要自己编写迭代器。但代码还是要写的,这次写图集合与深度优先遍历迭代器,大家如果对其它类型的图迭代器感兴趣的话,可自行编写。
3.代码实现
对于二维数组,从[0,0]开始,以广度优先顺序遍历。如对于
1 2
3 4
广度优先遍历顺序为1 2 3 4。
1 | package main |
输出:
➜ myproject go run main.go
[10 151 21]
[51 137 120]
[158 148 16]
0 : 10
1 : 151
2 : 137
3 : 51
4 : 21
5 : 120
6 : 16
7 : 148
8 : 158
代码写的比较简单,但是仍然能看到迭代器模式的优点。
- 可以轻易的变更遍历算法
- TwoDimensionalArray可继承于接口,面向接口编程,扩展性会进一步增强
总结
迭代器模式可能对于大部分研发同学来说是不需要的,但对于搞基础框架、搞语言的同学来说应该经常会用。对于迭代器模式,并不是说学习怎么使用,更重要的一点是需要感知设计模式的思想内核。