迭代器模式(Iterator)及代码实现

模式定义:

此模式 将 具有一定规律,可以迭代的 数据结构 的各种不同的遍历行为 单独放在一个类中实现;并且将这个类变为 可迭代对象;

此  模式重点是 将遍历行为放在单独类中实现,而不是 如何实现遍历行为;

代码中的例子:

  • 实际需求中, 如根据用户输入 存储一种树形的数据结构,并且按照用户喜好 输出数据结构的不同形式(如 深度遍历,广度遍历);  这时 需要考虑 也有可能在下版需求中 还有可能新增其他的遍历形式;  那么 可以考虑 把存储和遍历 这两个行为分成多个类去完成, 存储树结构行为放在一个类中; 遍历树结构放在另一个类中或者多个类中;

何时使用此模式:

实现方式:

该模式关键的角色:

抽象迭代器角色(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__使用

如果 聚合类 在需求中 只是简单的遍历查询操作,且不常修改,完全可以在一个类中实现; 没必要非要使用此模式, 此模式 适合在 多个遍历方式,且复杂易变时使用;

请不要为了使用设计模式而使用设计模式;

相关链接:

https://refactoringguru.cn/design-patterns/iterator

http://c.biancheng.net/view/1395.html

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值