设计模式之迭代器模式

发布时间 2024-01-12 02:53:41作者: 当时明月在曾照彩云归

1. 定义

在不暴露集合底层表现形式(列表、栈和树等)的情况下遍历集合中所有的元素

2. 口语化表述

假设某学校通知全校师生做核酸检测,要求应检尽检(即,每个人都要做)

现在,做核酸监测的工作人员已经到达现场,要求全校师生有序来检测

医护人员当然不知道全校师生怎么排序的,只关注每个人依次做检测并且要所有人都要检测过(即,遍历)

此时全校师生会在校方管理人员的规划下,划分检测顺序,依次做核酸检测

这就是迭代器模式,外来的核酸检测人员无需知道全校师生是怎么排序的,但是能每一个人都有序检测了

(下面的表述会沿用这个场景)

3. 源码示例

迭代器在编程语言中非常常见,例如在JavaScript中,遍历一个数组,最基础的做法就是对数组从头数到尾

let arr = [1, 2, 3]
for (let i = 0; i < arr.length; i++) {
    console.log(arr[i])
    // do something
}

那,遍历一个不好数的对象呢?比如,Map

Map对象可以看成一个一个的键值对,理应可以遍历,但是从外部来说,难以依次操作每一个键值对

能不能Map对象自身实现一个遍历函数呢?当然可以

查阅MDN文档:Map

可以知道,Map对象实现了可迭代协议,对外暴露出了遍历方法

实现了可迭代协议就是可迭代对象,可以使用for...of 循环进行遍历,例如下面的官方示例代码

const map1 = new Map()

map1.set('0', 'foo')
map1.set(1, 'bar')

const iterator1 = map1[Symbol.iterator]()

for (const item of iterator1) {
  console.log(item)
  // do something
}
// Expected output: Array ["0", "foo"]
// Expected output: Array [1, "bar"]

所以,封装一个对象时,如果后续需要涉及遍历操作,可以考虑使用迭代器模式,封装为可迭代对象

JavaScript. 总结

4.1 设计优点

  • 开闭原则

    假如有另外的核酸检测人员来了,全校师生的排序规则无需改变

  • 单一职责原则

    核酸检测人员、全校师生只负责做自己的事情

4.2 适用场景

  • 复杂的数据结构,隐藏其复杂性(出于使用便利性或安全性的考虑)

  • 遍历不同的甚至是无法预知的数据结构

    JavaScript代码中,只要实现了可迭代协议的对象,都可以使用for...of循环进行遍历,不管是什么样的数据结构

5. 参考资料

[1] 迭代器设计模式 (refactoringguru.cn)

[2] Map - JavaScript | MDN (mozilla.org)