iterator-pattern

有许多种方法可以把对象堆起来成为一个集合 (collection) 。你可以把它们放进数组、堆栈、列表或者是散列表 (Hashtable) 中, 这是你的自由。每一种都有它自己的优点和适合的使用时机,但总有一个时候,你 的客户想要遍历这些对象,而当他这么做时,你打算让客户看到你的实现吗?我们 当然希望最好不要!这太不专业。没关系,不要为你的工作担心,你将在本章中学习如何能让客户遍历你的对象而又无法窥视你存储对象的方式;也将学习如何创 建一些对象超集合 (super collection),能够一口气就跳过某些让人望而生畏的数 据结构。你还将学到•些关干对象职责的知识

引入

做的事情就相当于是给 map 和 数组 提供了一个统一的 迭代器接口, 通过 next() 和 hasNext 来判断是否可以继续遍历.

定义

迭代器模式提供一种方法顺序访问一个 聚合对象中的各个元素,而又不暴露其内部 的表示

迭代器模式让我们能游走于聚合内的每一个元素,而又不暴露其内部的表示。

把游走的任务放在迭代器上,而不是聚合上。 这样简化了聚合的接口和实现,也让责任各得其所

Note

实际上 js 的 iterator 就是对各种内置的数据结构都实现了 iterator pattern, 这样我们就可以直接使用 for of 循环, 遍历数组, map, set 等多样的数据结构

问题

看清现实,每次我们一有新菜单加入,就必须打开女招待实现 并加入更多的代码。这算不算是“违反开放 - 关闭原则”

这不是女招待的错。对于将她从菜单的实现卜解牺和提取遍历动作到迭代器,我们都做得很好。 但我们仍然将菜单处理成分离而独立的对象一我们需要一种一起管理它们的方法。

组合模式

组合模式允许你将对象组合成树形结构来 表现“整体/部分”层次结构。组合能让客户以 一致的方式处理个别对象以及对象组合

让我们以菜单为例思考这一切:这个模式能够创建一 个树形结构,在同♦个结构中处理嵌套菜单和菜单项 组。通过将菜单和项放在相同的结构中,我们创建了一 个“整体/部分”层次结构,即由菜单和菜单项组成的对 象树。但是可以将它视为一个整体,像是一个丰富的大 菜单“

其实就是一个树形的结构

到底怎么回事?首先你告诉我们 " 一个类.一个责任”,现在却给我们一个让一个类而两个责任的模式。组合模式不但要管理层次转构,而月还要执行菜单的操作

你的观察有几分真实性。我们可以这么说,组合模式以单一责任设 计原则换取透明性(transparency)。什么是透明性?通过让组件的 接口同时包含一些管理子节点和叶节点的操作,客户就可以将组合 和叶节点一视同仁。也就是说,一个元素究竟是组合还是叶节点, 对客户是透明的。

现在,我们在 MenuComponent 类中同时具有两种类型的操作。因为 客户有机会对一个元素做•些不恰当或是没右.意义的操作(例如试 图把菜单添加到菜单项),所以我们失去了一些“安全性”。这是 设计上的抉择,我们当然也可以采用另•种方向的段计,将责任区 分开来放在不同的接口中。这么一来,设计上就比较安全,但我们 也因此失去了透明性,客户的代码将必须用条件语句和 instanceof 操 作符处理不同类型的节点。

所以,回到你的问题,这是一个很典型的折衷案例。尽管我们受到 设计原则的指导,但是,我们总是需要观察某原则对我们的设计所 造成的影响。有时候,我们会故意做一些看似违反原则的事情。然 而,在某咋例子中,这是观点的问题;比方说,让笞理孩子的操作 (例如 add。、remove。、gctChildO)出现在叶节点中,似乎很不恰当, 但是换个视角来看,你可以把叶专点视为没有孩广的节点

通过递归实现组合的遍历

递归调用树形结构中的每个节点的 iterator

空迭代器

FAQ

迭代器模式的这张类图看起来很像我们所学过的另一个模式,你知道是哪个模式吗?提示: 子类决定要创建哪个对象