模式定义:
此模式 将 具有一定规律,可以迭代的 数据结构 的各种不同的遍历行为 单独放在一个类中实现;并且将这个类变为 可迭代对象;
此 模式重点是 将遍历行为放在单独类中实现,而不是 如何实现遍历行为;
代码中的例子:
- 实际需求中, 如根据用户输入 存储一种树形的数据结构,并且按照用户喜好 输出数据结构的不同形式(如 深度遍历,广度遍历); 这时 需要考虑 也有可能在下版需求中 还有可能新增其他的遍历形式; 那么 可以考虑 把存储和遍历 这两个行为分成多个类去完成, 存储树结构行为放在一个类中; 遍历树结构放在另一个类中或者多个类中;
何时使用此模式:
实现方式:
该模式关键的角色:
抽象迭代器角色(Abs Iterator): 定义访问和遍历 数据结构的接口;
具体迭代器角色(Concrete Iterator): 实现 抽象类中的各种方法; 并且 将类改为 可迭代对象(python中一起皆对象);
抽象聚合角色(Abs Iterator): 定义存,增,删,改 数据结构的方法;并 创建迭代器对象的接口;
具体聚合角色(Concrete Iterator):实现抽象类中的各种方法;
该模式的主要优缺点如下:
优点:
- 最大特点是符合单一职责原则: 聚合类 负责 对数据的 增删改; 而 迭代器类 负责对数据的 各种查询操作;
- 符合开闭原则:可实现新型的集合和迭代器并将其传递给现有代码,无需修改现有代码;
- 可以并行遍历同一集合, 因为每个迭代器对象都包含其自身的遍历状态;
- 你可以暂停遍历并在需要时继续;
缺点:
- 增加了 迭代器类,并且 将类转为可迭代类 需要内置的魔法方法;在一定程度上 增加了理解难度;
和 其他模式 的 比较:
- 可以和 组合模式 一起使用; 组合模式负责生成 可迭代的具有一定规律的 数据结构,如 树形结构; 然后 迭代器模式 负责 按照不同规则进行遍历; 这样可以做到 各个类 分工明确,灵活拓展;
- 与 访问者模式 比较: 都是将自身的数据交由其他类实现相关功能; 只是 访问者模式 的元素对象是完全的将自己作为参数传递给 访问者对象处理;而 迭代器模式 只是将自己的可迭代的数据结构交由 迭代器类处理;
示例代码部分:
# -*- coding: utf-8 -*-
"""
(C) Guangcai Ren <rgc@bvrft.com>
All rights reserved
create time '2020/12/30 19:20'
Usage:
迭代器模式使用示例
实现 二叉树的 广度遍历和深度遍历
"""
from copy import deepcopy
from queue import Queue
class Forefathers:
"""
组件 或 抽象构件 角色 主要 声明 公共方法
主要 负责 生产 迭代数据
"""
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
def __str__(self):
""""""
return self.name
def add(self, someone):
pass
def remove(self, someone):
pass
def __iter__(self):
"""
此方法 将对象转为可迭代对象
此方法 返回值必须是个可迭代对象;
:return:
"""
# 可迭代对象使用 IteratorForefathers的实例化;
# 也就是说 后续的 迭代获取下一个 数据 其实用的就是 IteratorForefathers实例化对象的 __next__方法
obj = IteratorForefathers(self)
obj.dfs_lf_list()
return obj
def dfs_lf_iter(self):
"""
此方法 是一个迭代方法;返回值是一个可迭代对象;
此处遍历方法如下:
深度优先遍历
前序遍历
:return:
Usage:
>>> for item in Forefathers('','','').dfs_lf_iter():
>>> print(item)
"""
obj = IteratorForefathers(self)
obj.dfs_lf_list()
return obj
def dfs_rf_iter(self):
"""
此方法 是一个迭代方法;返回值是一个可迭代对象;
此处遍历方法如下:
深度优先遍历
后序遍历
:return:
Usage:
>>> for item in Forefathers('','','').dfs_rf_iter():
>>> print(item)
"""
obj = IteratorForefathers(self)
obj.dfs_rf_list()
return obj
def bfs_iter(self):
"""
此方法 是一个迭代方法;返回值是一个可迭代对象;
此处遍历方法如下:
广度优先遍历
:return:
Usage:
>>> for item in Forefathers('','','').bfs_iter():
>>> print(item)
"""
obj = IteratorForefathers(self)
obj.bfs_list()
return obj
class Parents(Forefathers):
"""
容器 或 组合 角色
父母 类 可以有后代
"""
def __init__(self, name, age, gender):
"""
:param name:
:param age:
:param gender:
"""
super(Parents, self).__init__(name, age, gender)
self.children = []
def add(self, *someone):
"""
新增 子孙
:param someone:
:return:
"""
self.children += someone
def remove(self, someone):
"""
移出 祖籍
:param someone:
:return:
"""
self.children.remove(someone)
class Child(Forefathers):
"""
叶节点 角色
孩童 类 没有后代
"""
def __init__(self, name, age, gender):
"""
:param name:
:param age:
:param gender:
"""
super(Child, self).__init__(name, age, gender)
class IteratorForefathers:
"""
迭代器类
主要负责 提供各种不同的遍历方式
将 各种遍历的代码 和 生产 迭代数据 的代码 分离开;
"""
def __init__(self, been_iter):
"""
初始化
:param been_iter: 被迭代的嵌套层级数据
"""
self.been_iter = been_iter
self._p = 0
self.name_list = []
self.queue = Queue()
def dfs_lf_list(self, been_iter=None):
"""
先将 被迭代的 嵌套层级数据 按照一定规则剥离层级关系 抽取到一个list中;目的为了在__next__方法中方便遍历
如 原来是 [[1,2],3,[4,[5,[6,[7]]]]] 转为:[1,2,3,4,5,6,7]
此处遍历方法如下:
深度优先遍历
前序遍历
:return:
"""
if not been_iter:
been_iter = self.been_iter
self.name_list.append(been_iter.name)
if hasattr(been_iter, 'children'):
for item in been_iter.children:
self.dfs_lf_list(item)
def dfs_rf_list(self, been_iter=None):
"""
先将 被迭代的 嵌套层级数据 按照一定规则剥离层级关系 抽取到一个list中;目的为了在__next__方法中方便遍历
如 原来是 [[1,2],3,[4,[5,[6,[7]]]]] 转为:[1,2,3,4,5,6,7]
此处遍历方法如下:
深度优先遍历
后序遍历
:return:
"""
if not been_iter:
been_iter = self.been_iter
self.name_list.append(been_iter.name)
if hasattr(been_iter, 'children'):
children = deepcopy(been_iter.children)
children.reverse()
for item in children:
self.dfs_rf_list(item)
def bfs_list(self, been_iter=None):
"""
先将 被迭代的 嵌套层级数据 按照一定规则剥离层级关系 抽取到一个list中;目的为了在__next__方法中方便遍历
如 原来是 [[1,2],3,[4,[5,[6,[7]]]]] 转为:[1,2,3,4,5,6,7]
此处遍历方法如下:
广度优先遍历
思路:使用队列的先入先出特点,在每取出一个数据后,都要把这个数据的 所有子节点放入队列中; 从而保证 横向遍历(广度优先遍历)
:return:
"""
if not been_iter:
been_iter = self.been_iter
# 先给出自己
self.name_list.append(been_iter.name)
if hasattr(been_iter, 'children'):
# 把自己的子节点放到 队列里
for item in been_iter.children:
self.queue.put(item)
# 如果队列中没有数据,则跳过,否则 程序一直等待
if len(self.queue.queue) > 0:
# 取出队列里的第一个数据(先入先出规则)
node = self.queue.get()
# 对第一个数据执行迭代
self.bfs_list(node)
def __next__(self):
"""
获取下一个数据
:return:
"""
try:
val = self.name_list[self._p]
self._p += 1
except IndexError:
# 停止迭代的方法
raise StopIteration
return val
def __iter__(self):
"""
此方法 将对象转为可迭代对象
:return:
"""
return self
if __name__ == '__main__':
"""
运行时分为2部分;先生产迭代数据;再进行各种遍历
"""
print('生产 迭代数据部分start', '*' * 10)
root = Parents('第一代祖宗', 1800, 'man')
sec_man = Parents('第二代男祖宗', 1840, 'man')
sec_man1 = Parents('第二代男1祖宗', 1840, 'man')
sec_woman = Parents('第二代女祖宗', 1840, 'woman')
root.add(sec_man, sec_woman, sec_man1)
last_one = Child('最早灭绝一代', 1860, 'man')
sec_man.add(last_one)
third_woman = Parents('第三代女祖宗', 1860, 'woman')
sec_woman.add(third_woman)
third_man = Parents('第三代男祖宗', 1860, 'man')
sec_woman.add(third_man)
four_man = Parents('第四代男祖宗', 1890, 'man')
third_woman.add(four_man)
last_one = Child('最后一代', 1890, 'man')
third_woman.add(last_one)
print('生产 迭代数据部分end', '*' * 10)
print('开始执行 默认的迭代方式(前序遍历)', '*' * 10)
for item in root.__iter__(): # 被迭代对象默认调用的就是__iter__方法
print(item)
for item in root: # 被迭代对象默认调用的就是__iter__方法
print(item)
print('开始执行 前序遍历', '*' * 10)
for item in root.dfs_lf_iter():
print(item)
print('开始执行 后序遍历', '*' * 10)
for item in root.dfs_rf_iter():
print(item)
print('开始执行 广度优先遍历', '*' * 10)
for item in root.bfs_iter():
print(item)
总结:
此模式 需要将 遍历数据的类变为可迭代类, 可以查看如下网址: python __iter__,__next__使用
如果 聚合类 在需求中 只是简单的遍历查询操作,且不常修改,完全可以在一个类中实现; 没必要非要使用此模式, 此模式 适合在 多个遍历方式,且复杂易变时使用;
请不要为了使用设计模式而使用设计模式;
相关链接: