持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第12天,点击查看活动详情次
- 本文主要介绍iOS设计模式中的
迭代器模式
,迭代器模式我们在swift的数组的一些高阶函数也是根据迭代器实现,比如我们的filter
等。
1. 什么是迭代器模式
我们每次从自动售货机买汽水
的时候,顾客选择了汽水,付钱后我们就拿到了。显然自动售货机里不止装了一瓶汽水。顾客只是不知道这些瓶子这些饮料是怎么放入售卖柜的,又是怎么出来的。内部货架不知道发售的事情,它唯一的作用就是“收纳”
饮料。它依赖分配器来进行所有的分配和出货
操作。内部的货架就像mvc对象结构
中的模型,或者只是数据结构。其唯一职责就是维护一个数据集合。
大部分集合
使用简单列表存储元素。 但有些集合还会使用栈、 树、 图
和其他复杂的数据结构。
无论集合的构成方式如何, 它都必须提供某种访问元素
的方式, 便于其他代码使用其中的元素。 集合应提供一种能够遍历元素的方式, 且保证它不会周而复始地访问同一个元素。
如果你的集合基于列表, 那么这项工作听上去仿佛很简单。 但如何遍历复杂数据结构
(例如树) 中的元素呢? 例如, 今天你需要使用深度优先算法来遍历树结构, 明天可能会需要广度优先算法; 下周则可能会需要其他方式 (比如随机存取树中的元素)。
不断向集合中添加遍历算法
会模糊其 “高效存储数据”
的主要职责。 此外, 有些算法可能是根据特定应用订制的, 将其加入泛型集合类中会显得非常奇怪。
另一方面, 使用多种集合的客户端代码可能并不关心存储数据的方式。 不过由于集合
提供不同的元素访问
方式, 你的代码将不得不与特定集合类进行耦合
。 在面向对象的软件中,针对抽象几何迭代
的行为的设计模式叫做迭代器。迭代器提供了一种顺序访问聚合对象中元素的方法,而无需暴漏结构的底层表示和细节
。
迭代器:提供了一种顺序访问一个聚合对象中各个元素,而又不需暴漏该对象的内部表示。
2. 迭代器种类
迭代器分为外部迭代器
和内部迭代器
,外部迭代器是让客户端直接操作迭代的过程,所以客户端需要知道外部迭代器才能使用
。另一种情况是,集合对象
在其内部维护并操作一个外部迭代器
,提供内部迭代器的典型的集合对象为客户端定义一个接口
。
外部迭代器 | 内部迭代器 |
---|---|
客户端需要知道外部选代器才能使用,但是它为客户端提供了更多的控制 | 客户端不需要知道任何外部选代器,而是可以通过集合对象的特殊接口,或者一次访间--个元素,或者向集合中的每个元素发送消息 |
客户端创建并维护外部迭代器 | 集合对象本身创建井维护它的外部选代器 |
客户端可以使用不同外部迭代器实现多种类型的遍历 | 集合对象可以在不修改客户端代码的情况下,选择不同的外部迭代器 |
3. 什么时候使用迭代器模式
- 需要访问
组合对象
的内容,而又不暴漏
其内部表示; - 需要通过
多种方式
遍历组合对象; - 需要提供一个
统一的接口
,用来遍历各种类型的组合对象
4.代码展示
import XCTest
/// This is a collection that we're going to iterate through using an iterator
/// derived from IteratorProtocol.
class WordsCollection {
fileprivate lazy var items = [String]()
func append(_ item: String) {
self.items.append(item)
}
}
extension WordsCollection: Sequence {
func makeIterator() -> WordsIterator {
return WordsIterator(self)
}
}
/// Concrete Iterators implement various traversal algorithms. These classes
/// store the current traversal position at all times.
class WordsIterator: IteratorProtocol {
private let collection: WordsCollection
private var index = 0
init(_ collection: WordsCollection) {
self.collection = collection
}
func next() -> String? {
defer { index += 1 }
return index < collection.items.count ? collection.items[index] : nil
}
}
/// This is another collection that we'll provide AnyIterator for traversing its
/// items.
class NumbersCollection {
fileprivate lazy var items = [Int]()
func append(_ item: Int) {
self.items.append(item)
}
}
extension NumbersCollection: Sequence {
func makeIterator() -> AnyIterator<Int> {
var index = self.items.count - 1
return AnyIterator {
defer { index -= 1 }
return index >= 0 ? self.items[index] : nil
}
}
}
/// Client does not know the internal representation of a given sequence.
class Client {
// ...
static func clientCode<S: Sequence>(sequence: S) {
for item in sequence {
print(item)
}
}
// ...
}
/// Let's see how it all works together.
class IteratorConceptual: XCTestCase {
func testIteratorProtocol() {
let words = WordsCollection()
words.append("First")
words.append("Second")
words.append("Third")
print("Straight traversal using IteratorProtocol:")
Client.clientCode(sequence: words)
}
func testAnyIterator() {
let numbers = NumbersCollection()
numbers.append(1)
numbers.append(2)
numbers.append(3)
print("\nReverse traversal using AnyIterator:")
Client.clientCode(sequence: numbers)
}
}
复制代码
执行结果
Straight traversal using IteratorProtocol:
First
Second
Third
Reverse traversal using AnyIterator:
3
2
1
复制代码
5.总结
迭代器主要配合遍历循环计算
,提供了一种顺序访问聚合对象
中元素的方法,而无需暴漏
结构的底层表示和细节。我们对于简单的结构可以直接使用Swift或者Object-c提供的迭代器
遍历,对于复杂的我们组合结构类型则需要自定义一个外部的迭代器
,来附和我们的需求。