1. 简介
迭代器模式是一种行为设计模式, 让你能够在不暴露集合底层数据结构形式(列表、栈、队列、树和图等)的情况下遍历集合中所有的元素。
2. 迭代器模式的结构
classDiagram
class Client {
+client()
}
class Iterable {
<<iterface>>
+__iter__(): Iterator
}
class ConcreteIterable {
-collection: List[Any]
+add(element: Any)
+__iter__(): Iterator
}
class Iterator {
<<interface>>
+__iter__(): Iterator
+__next__(): Any
}
class ConcreteIterator {
-collection: List[Any]
-index: int
+__iter__(): ConcreteIterator
+__next__(): Any
}
Iterable <|.. ConcreteIterable
Iterable ..> Iterator
Iterator <|.. ConcreteIterator
Client --> Iterable
Client --> Iterator
-
迭代器(Iterator)接口声明了遍历集合所需的操作:获取下一个元素、获取当前位置和重新开始迭代等。
-
具体迭代器(Concrete Iterators)实现遍历集合的一种特定算法。迭代器对象必须跟踪自身遍历的进度。这使得多个迭代器可以相互独立地遍历同一集合。
-
可迭代的集合(Iterable)接口声明一个或多个方法来获取与集合兼容的迭代器。请注意,返回方法的类型必须被声明为迭代器接口,因此具体集合可以返回各种不同种类的迭代器。
-
具体集合(Concrete Iterable)会在客户端请求迭代器时返回一个特定的具体迭代器类实体。你可能会琢磨,剩下的集合代码在什么地方呢?不用担心,它也会在同一个类中。只是这些细节对于实际模式来说并不重要,所以我们将其省略了而已。
-
客户端(Client)通过集合和迭代器的接口与两者进行交互。这样一来客户端无需与具体类进行耦合,允许同一客户端代码使用各种不同的集合和迭代器。客户端通常不会自行创建迭代器,而是会从集合中获取。但在特定情况下,客户端可以直接创建一个迭代器(例如当客户端需要自定义特殊迭代器时)。
当然,在简单的应用场景下,迭代器接口和可迭代的集合接口往往可以省略。
3. 迭代器模式的优缺点以及使用场景
优点:
- 简化遍历操作:迭代器模式提供了一种统一的遍历接口,使得客户端无需关心集合的内部数据结构,可以简单地遍历集合中的元素。
- 隔离集合与遍历逻辑:迭代器模式将集合的遍历逻辑封装在迭代器中,使得集合和遍历逻辑能够独立变化,从而提高了代码的灵活性和可维护性。
- 支持多种遍历方式:迭代器模式可以支持多种遍历方式,如顺序遍历、逆序遍历、按条件遍历等,对树或者图的集合形式,还可以自定义深度优先遍历、宽度优先遍历,因此,客户端可以根据需要选择合适的遍历方式。
- 简化客户端代码:使用迭代器模式可以简化客户端的代码,使得客户端只需关注业务逻辑,而无需关心集合的遍历细节。
缺点:
- 增加类和对象的数量:迭代器模式会引入额外的迭代器类和迭代器对象,可能会增加系统的复杂性。
- 不适合所有集合:迭代器模式适用于遍历访问聚合对象中的元素,但并不是所有集合都适合使用迭代器模式,特别是对于一些固定大小或结构简单的集合,使用迭代器可能会显得繁琐。
使用场景:
- 需要统一遍历接口:当集合的遍历逻辑复杂或需要多种遍历方式时,可以使用迭代器模式统一遍历接口,简化客户端的代码。
- 需要隔离集合与遍历逻辑:当集合的内部结构可能经常变化,或者需要对集合和遍历逻辑进行独立扩展时,可以使用迭代器模式隔离集合与遍历逻辑,提高代码的灵活性和可维护性。
- 需要支持多种遍历方式:当需要支持多种遍历方式,如顺序遍历、逆序遍历、按条件遍历等时,可以使用迭代器模式灵活地选择合适的遍历方式。
- 需要简化客户端代码:当客户端需要遍历访问集合中的元素,但不想关心集合的内部结构和遍历细节时,可以使用迭代器模式简化客户端的代码。
4. 练习:【设计模式专题之迭代器模式】19-学生名单
"""
【设计模式专题之迭代器模式】19-学生名单
时间限制:1.000S 空间限制:256MB
题目描述
小明是一位老师,在进行班级点名时,希望有一个学生名单系统,请你实现迭代器模式提供一个迭代器使得可以按顺序遍历学生列表。
输入描述
第一行是一个整数 N (1 <= N <= 100), 表示学生的数量。
接下来的 N 行,每行包含一个学生的信息,格式为 姓名 学号
输出描述
输出班级点名的结果,即按顺序遍历学生列表,输出学生的姓名和学号
输入示例
3
Alice 1001
Bob 1002
Charlie 1003
输出示例
Alice 1001
Bob 1002
Charlie 1003
"""
from typing import List
class Student:
def __init__(self, name: str, number: str):
self.name = name
self.number = number
def attend(self):
print(f"{self.name} {self.number}")
class IterableStudents:
def __init__(self):
self.students: List[Student] = []
def add(self, student: Student):
self.students.append(student)
def __iter__(self):
return StudentsIterator(self.students)
class StudentsIterator:
def __init__(self, students: List[Student]):
self.students = students
self.index = 0
def __iter__(self):
return self
def __next__(self):
try:
student = self.students[self.index]
except IndexError:
raise StopIteration
else:
self.index += 1
return student
def client():
students = IterableStudents()
n = int(input())
for _ in range(n):
name, number = input().split()
student = Student(name, number)
students.add(student)
iterator = iter(students)
while True:
try:
student = next(iterator)
except StopIteration:
break
else:
student.attend()
if __name__ == "__main__":
client()