持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第14天
介绍
迭代器模式(Iterator),提供一种方法顺序访问一个聚合对象中的各种元素,而又不暴露该对象的内部表示。
迭代器模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可让外部代码透明地访问集合内部的数据。
聚合对象用来存储一系列数据。其主要有两个职责:一是存储数据;二是遍历数据。从依赖性来看,前者是聚合对象的基本职责;而后者既是可变化的,又是可分离的。这时,将遍历数据的行为从聚合对象中分离出来,封装在一个被称之为“迭代器”的对象中,由迭代器来提供遍历聚合对象内部数据的行为,这将简化聚合对象的设计,更符合“单一职责原则”的要求。
使用场景
-
访问一个聚合对象的内容而无须暴露它的内部表示。
-
需要为聚合对象提供多种遍历方式。
-
为遍历不同的聚合结构提供一个统一的接口。
应用实践
迭代器的分类
-
内部迭代器:内部迭代器的特点是内部已经定义好了迭代规则,完全接手整个迭代过程,外部只需要一次初始调用。
-
外部迭代器:外部迭代器必须显示的请求迭代下一个元素。相比于内部迭代器,外部迭代器增加了一些调用的复杂度,但相对也增强了迭代器的灵活性,我们可以手工的控制迭代的过程或者顺序。
-
倒序迭代器
-
中止迭代器:中止迭代器是可以像普通for循环中的break一样,提供一种跳出循环的方法。我们约定如果回调函数的执行结果返回false,则提前终止循环。
实现
class Iterator {
constructor(container) {
this.list = container.list
this.index = 0
}
next() {
if (this.hasNext()) {
return this.list[this.index++]
}
}
hasNext() {
if (this.index >= this.list.length) {
return false
}
return true
}
}
class Container {
constructor(list) {
this.list = list
}
// 生成遍历器
getIterator() {
return new Iterator(this)
}
}
let container = new Container([1, 2, 3, 4, 5, 6])
let iterator = container.getIterator()
while (iterator.hasNext()) {
console.log(iterator.next());
}
汇总
优点特性
- 访问一个聚合对象的内容,而无须暴露它的内部表示。
- 遍历任务交由迭代器完成,这简化了聚合类。
- 它支持以不同方式遍历一个聚合,甚至可以自定义迭代器的子类以支持新的遍历方式。
- 增加新的聚合类和迭代器类都很方便,无须修改原有代码。
- 封装性良好,为遍历不同的聚合结构提供一个统一的接口,从而支持同样的算法在不同的聚合结构上进行操作。
缺点弊端
-
由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性。
-
在遍历的过程中,更改迭代器所在的聚合结构可能导致出现异常。所以使用迭代器只能对集合进行遍历,不能在遍历的同时增加或删除集合中的元素。