iOS设计模式之迭代器

持续创作,加速成长!这是我参与「掘金日新计划 · 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提供的迭代器遍历,对于复杂的我们组合结构类型则需要自定义一个外部的迭代器,来附和我们的需求。

猜你喜欢

转载自juejin.im/post/7107622150198018079