iOS中的设计模式(十二)- 迭代器模式(Iterator Pattern)在 iOS 开发中的实践

一. 引言

很多开发者第一次接触迭代器模式时都会有一个疑问:为什么在实际开发中几乎没有写过迭代器?

但其实,在日常 iOS 开发中,我们几乎每天都会遍历数组、字典或者集合。例如:

Swift 复制代码
for item in array {
    print(item)
}

或者:

Swift 复制代码
array.forEach { item in
    print(item)
}

这些写法已经非常自然,以至于我们很少会思考:这些遍历背后的实现机制是什么?

事实上,这正是经典设计模式中的 迭代器模式(Iterator Pattern)

不过在现代 Swift 开发中,我们很少需要自己实现迭代器,因为 Swift 标准库已经把这一模式内置到了语言层面。但理解它依然很有价值,因为很多系统 API 和高级集合操作都是基于这一模式实现的。

本文我们就来一起看看 什么是迭代器模式,以及它在 iOS 开发中的实际应用方式。

二. 什么是迭代器

迭代器模式的核心思想是:在不暴露集合内部结构的情况下,顺序访问集合中的元素。

换句话说:

  • 集合负责存储数据
  • 迭代器负责遍历数据

调用者只需要关心下一个元素是谁。而不需要关心集合内部到底是数组、链表还是树。

这就实现了 访问逻辑与数据结构的解耦。

三. 传统迭代器模式

在经典设计模式中,迭代器通常包含以下几个角色:

Iterator(迭代器接口)

负责定义遍历方法,例如:

Swift 复制代码
next()
hasNext()

ConcreteIterator(具体迭代器)

真正实现遍历逻辑。

Aggregate(集合接口)

定义创建迭代器的方法。

ConcreteAggregate(具体集合)

具体的数据存储结构。

Swift 复制代码
Aggregate
   │
   └── createIterator()

Iterator
   ├── next()
   └── hasNext()

调用者通过迭代器来访问集合,而不是直接访问集合内部数据。

四. Swift 中的迭代器

在 Swift 中,这一模式已经被标准库封装为两个核心协议:

Swift 复制代码
Sequence
IteratorProtocol

IteratorProtocol

定义了最核心的方法:

Swift 复制代码
protocol IteratorProtocol {
    associatedtype Element
    mutating func next() -> Element?
}

next() 每次返回一个元素,当没有元素时返回 nil。

Sequence

Sequence 表示 一个可被遍历的集合。

Swift 复制代码
protocol Sequence {
    associatedtype Iterator: IteratorProtocol
    func makeIterator() -> Iterator
}

当一个类型遵守 Sequence 时,就可以被 for-in 遍历。

例如:

Swift 复制代码
let array = [1,2,3]

var iterator = array.makeIterator()

while let value = iterator.next() {
    print(value)
}

而我们平时写的:

Swift 复制代码
for value in array {
    print(value)
}

五. 实现一个自定义迭代器

接下来我们实现一个简单的例子:一副扑克牌 Deck。

目标是让它支持这样的遍历方式:

Swift 复制代码
for card in deck {
    print(card)
}

5.1 定义 Card 和 Deck

Swift 复制代码
struct Card {
    let suit: String
    let number: Int
}

class CardDeck {
    
    private var cards: [Card] = []
    
    init() {
        let suits = ["♠️","♥️","♣️","♦️"]
        
        for suit in suits {
            for number in 1...13 {
                cards.append(Card(suit: suit, number: number))
            }
        }
    }
}

这里我们创建了一副标准的 52 张牌。

5.2 创建 DeckIterator

Swift 复制代码
struct CardDeckIterator: IteratorProtocol {
    
    private var cards: [Card]
    private var index = 0
    
    init(cards: [Card]) {
        self.cards = cards
    }
    
    mutating func next() -> Card? {
        
        guard index < cards.count else {
            return nil
        }
        
        let card = cards[index]
        index += 1
        
        return card
    }
}

这个迭代器负责:

  1. 记录当前位置 index
  2. 每次返回一张牌
  3. 遍历结束返回 nil

5.3 让 Deck 支持遍历

接下来让 CardDeck 遵守 Sequence:

Swift 复制代码
extension CardDeck: Sequence {
    
    func makeIterator() -> CardDeckIterator {
        return CardDeckIterator(cards: cards)
    }
}

现在就可以这样使用了:

Swift 复制代码
let deck = CardDeck()

for card in deck {
    print(card)
}

六. 关于自己实现迭代器

但其实在客户端开发中,我们确实很少自己来写迭代器。主要是Swift的标准库就已经实现了,我们常用的集合类型:

Swift 复制代码
Array
Set
Dictionary

全部已经遵守 Sequence,因此我们天然就拥有了遍历能力。

除了我们常用的遍历函数,Swift还提供了很多基于迭代器的高级函数:

Swift 复制代码
map
filter
reduce
compactMap
forEach

我们使用起来又方便,又快捷。

另外就是通常在在客户端需要处理的业务数据结构都很简单,大多数APP中,我们就只需要使用 Array或者Dictionary就够了。很少会自己来实现复杂的集合结构,因此也就很少需要手写迭代器。

七. 结语

迭代器模式是一个非常经典的设计模式,它解决的问题其实非常简单:如何在不暴露内部结构的情况下遍历集合。

在现代 Swift 开发中,我们很少需要自己实现迭代器,因为Sequence,IteratorProtocol 已经把这一模式内置到了语言层面。

但理解它依然非常重要。

相关推荐
sanshizhang2 小时前
设计模式-责任链模式
java·设计模式·责任链模式
逆境不可逃2 小时前
【从零入门23种设计模式16】行为型之迭代器模式
java·开发语言·数据结构·算法·设计模式·职场和发展·迭代器模式
geovindu2 小时前
python: Singleton Pattern
开发语言·python·单例模式·设计模式
JTCC2 小时前
Java 设计模式西游篇 - 第七回:责任链模式过难关 通关文牒层层批
java·设计模式·责任链模式
JTCC2 小时前
Java 设计模式西游篇 - 第九回:外观模式简化繁 如来神掌一指定
java·设计模式·外观模式
geovindu2 小时前
python: Prototype Pattern
python·设计模式·原型模式
JTCC2 小时前
Java 设计模式西游篇 - 第三回:策略模式换法宝 三打白骨精变招
java·设计模式·策略模式
铁手飞鹰2 小时前
[精通Python设计模式]笔记
笔记·设计模式