Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >迭代器模式

迭代器模式

作者头像
小蜜蜂
修改于 2019-07-16 09:25:13
修改于 2019-07-16 09:25:13
65000
代码可运行
举报
文章被收录于专栏:明丰随笔明丰随笔
运行总次数:0
代码可运行

迭代器模式的定义

提供一种统一的方法遍历一个集合中的各个元素,而不关心集合的内部实现。

迭代器模式的目的

在面向对象编程里,迭代器模式是一种最简单也最常见的设计模式。它可以让用户透过特定的接口访问集合中的每一个元素而不用了解底层的实现。一般实现一个集合的方法有:数组,链表,哈希表等等,每种集合因为底层实现不同,遍历集合的方法也不同。对于数组或者列表,用户需要在对集合了解很清楚的前提下,可以自行遍历对象,但是对于hash表来说,用户遍历起来就比较麻烦,而且暴露了集合类的内部表示给用户,数据也会不安全。而引入了迭代器方法后,用户用起来就简单的多了,并且更加安全。迭代器模式在客户访问类与集合类之间插入一个迭代器,这分离了聚合对象与其遍历行为,对客户也隐藏了其内部细节,且满足“单一职责原则”和“开闭原则”。所以,如果我们对各种集合的都实现了迭代器接口,就可以使存储数据和遍历数据的职责分离,并且让外部代码可以透明并统一地访问集合内部的数据,简化了遍历方式,还提供了良好的封装性,用户只需要得到迭代器就可以遍历,而对于遍历算法则不用关心。

迭代器模式的优点

1.访问一个聚合对象的内容而无须暴露它的内部表示。

2.遍历任务交由迭代器完成,这简化了集合类。

3.它支持以不同方式遍历一个聚合,甚至可以自定义迭代器的子类以支持新的遍历。

4.增加新的集合类和迭代器类都很方便,无须修改原有代码。

5.封装性良好,为遍历不同的聚合结构提供一个统一的接口。

迭代器模式的缺点

增加了类的个数,这在一定程度上增加了系统的复杂性。

迭代器模式的应用场景

1.需要为聚合对象提供多种遍历方式。

2.需要为遍历不同的聚合结构提供一个统一的接口。

3.访问一个聚合对象的内容而无须暴露其内部细节的表示。

迭代器模式的结构

迭代器模式把存储数据和遍历数据的职责分离,所以它需要2个类:集合类和迭代器类。因为需要接口编程,所以,在迭代器模式中,抽象了2个接口,一个是集合接口,另一个是迭代器接口,具体的角色如下:

1.抽象聚合(Aggregate)角色:定义存储、添加、删除聚合对象以及创建迭代器对象的接口。

2.具体聚合(ConcreteAggregate)角色:实现抽象聚合类,返回一个具体迭代器的实例。

3.抽象迭代器(Iterator)角色:定义访问和遍历聚合元素的接口,通常包含 hasNext()、first()、next() 等方法。

4.具体迭代器(Concretelterator)角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。

具体的结构类图如下所示:

迭代器模式的经典实现

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface Aggregate
{
    void add(object obj);
    void remove(object obj);
    Iterator getIterator();
}

public interface Iterator
{
    object first();
    object next();
    bool hasNext();
}

public class ConcreteAggregate : Aggregate
{
    private List<object> _list = new List<object>()
    {
        "Nestor","Liu"
    };

    public void add(object obj)
    {
        _list.Add(obj);
    }

    public Iterator getIterator()
    {
        return new ConcreteIterator(_list);
    }

    public void remove(object obj)
    {
        _list.Remove(obj);
    }
}

public class ConcreteIterator : Iterator
{
    private List<object> _list = null;
    private int _index = -1;

    public ConcreteIterator(List<object> list)
    {
        _list = list;
    }

    public object first()
    {
        _index = 0;
        object obj = _list[_index];
        return obj;
    }

    public bool hasNext()
    {
        return _list.Count() > _index + 1;
    }

    public object next()
    {
        return hasNext() ? _list[++_index] : null;
    }
}

ConcreteAggregate aggregate = new ConcreteAggregate();
Iterator iterator = aggregate.getIterator();

while (iterator.hasNext())
{
    Console.WriteLine(iterator.next().ToString());
}

.NET中迭代器模式的规范

在.NET下,迭代器模式中的聚集接口和迭代器接口都已经存在了,其中IEnumerator接口扮演的就是迭代器角色,IEnumberable接口则扮演的就是抽象聚集的角色,只有一个GetEnumerator()方法,关于这两个接口的定义可以自行参考MSDN。根据定义,Microsoft .NET Framework集合是至少实现IEnumerable<T>(或非泛型IEnumerable接口)的类。此接口至关重要,因为至少必须实现IEnumerable<T>的方法,才支持迭代集合。IEnumerable和IEnumerator接口的类图:

这样实现的好处在集合类不直接支持IEnumerator接口,而是直接支持另一种接口IEnumerable,其唯一方法是GetEnumerator。此方法用于返回支持 IEnumerator的对象。IEnumerator的对象就像是序列中的“游标”或“书签”。一个集合可以有多个“书签”,移动其中任何一个都可以枚举集合,与其他枚举器互不影响。

.NET规范实现代器模式:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class MyEnumerable : IEnumerable
{
    private List<object> _list = new List<object>()
    {
        "Nestor", "Liu"
    };

    public IEnumerator GetEnumerator()
    {
        return new MyEnumerator(_list);
    }
}

public class MyEnumerator : IEnumerator
{
    private int _index = -1;
    private List<object> _list;

    public MyEnumerator(List<object> list)
    {
        _list = list;
    }

    public object Current
    {
        get
        {
            if (_index == -1 || _index >= _list.Count())
            {
                throw new IndexOutOfRangeException();
            }
            return _list[_index];
        }
    }

    public bool MoveNext()
    {
        return _list.Count() > ++_index;
    }

    public void Reset()
    {
        throw new NotImplementedException();
    }
}

yield语法糖

通过使用yield定义迭代器,可在实现自定义集合类型迭代器模式时无需其他显式类,使用yield return语句可一次返回一个元素。迭代器方法运行到yield return语句时,会返回一个expression,并保留当前在代码中的位置。下次调用迭代器函数时,将从该位置重新开始执行。可以使用 yield break 语句来终止迭代。C#代码示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class MyEnumerable2 : IEnumerable
{
    public IEnumerator GetEnumerator()
    {
        yield return "Nestor";
        yield return "Liu";
    }
}

对于上面yield语法写法虽然没有显式的定义IEnumerator的实现,但是背后的原理是一样的,C#编辑器编译成的IL代码会包含IEnumerator的实现。

.NET Framework中迭代器模式的应用

C#的foreach语句其实就是迭代器模式。任何可以使用foreach进行遍历的对象,它一定是实现了IEnumerable接口。任何实现了IEnumerable接口的对象集合都可以使用foreach遍历。

foreach语句的写法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void ForeachTest()
{
    int[] values = new int[] { 1, 2, 3, 4, 5 };

    foreach (int i in values)
    {
        Console.Write(i.ToString() + " ");
    }
    Console.WriteLine();
}

其实等价于下面的写法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void IteratorTest()
{
    int[] values = new int[] { 1, 2, 3, 4, 5 };
    IEnumerator e = ((IEnumerable)values).GetEnumerator();
    while (e.MoveNext())
    {
        Console.Write(e.Current.ToString() + " ");
    }
    Console.WriteLine();
}

对于上面两种C#写法,C#编辑器编译成的IL代码是一致的。

迭代器执行过程

以下代码从迭代器方法返回IEnumerable<string>,然后遍历其元素。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
IEnumerable<string> elements = MyIteratorMethod();
foreach (string element in elements)
{
   ...
}

调用MyIteratorMethod并不执行该方法的主体。 相反,会将调用的控制权返回到elements变量中。在foreach循环迭代时,将调用elements的MoveNext方法。 此调用将执行MyIteratorMethod的主体,直至到达下一个yield return语句。yield return 语句返回的表达式不仅决定了循环体使用的element变量值,还决定了elements的Current属性。我们通过一张图来看迭代器执行过程:

迭代器模式的使用感受

迭代器模式是与集合类紧密绑定在一起的,一般来说,我们只要实现一个集合类,就应该同时提供这个集合的迭代器,就像C#中的Collection,List、Set、Map等,这些集合都有自己的迭代器。假如我们要实现一个这样的新的容器,当然也需要引入迭代器模式,给我们的容器实现一个迭代器,这样客户在遍历我们的集合时,可以享受到一致的体验。

谢谢观看!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-06-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 明丰随笔 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
「聊设计模式」之迭代器模式(Iterator)
🏆本文收录于《聊设计模式》专栏,专门攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎持续关注&&收藏&&订阅!
bug菌
2023/11/15
3680
「聊设计模式」之迭代器模式(Iterator)
重温设计模式 --- 迭代器模式
迭代器模式是一种行为型设计模式,它允许按照特定顺序遍历集合对象的元素,同时不暴露集合的内部结构。这样做可以让客户端代码不依赖于集合对象的具体实现,从而提高代码的灵活性和可重用性。
Niuery Diary
2023/10/22
1440
重温设计模式 --- 迭代器模式
设计模式之迭代器模式
Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
beginor
2020/08/10
3080
设计模式之迭代器模式
设计模式-迭代器模式
迭代器模式 迭代器(Iterator)模式的定义:提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。迭代器模式是一种对象行为型模式,其主要优点如下。 1.优点 访问一个聚合对象的内容而无须暴露它的内部表示。 遍历任务交由迭代器完成,这简化了聚合类。 它支持以不同方式遍历一个聚合,甚至可以自定义迭代器的子类以支持新的遍历。 增加新的聚合类和迭代器类都很方便,无须修改原有代码。 封装性良好,为遍历不同的聚合结构提供一个统一的接口。 2.确定 增加了类的个数,这在一定程度上增加了系
cwl_java
2019/10/26
2870
设计模式实战-迭代器模式,最常用的设计模式之一
迭代器模式(Iterator Pattern)又称为游标(Cursor)模式,是最常被使用的几个模式之一,被广泛地应用到 Java 的 API 中。例如,Java 的集合(Collection)框架中,就广泛使用迭代器来遍历集合中的元素。
架构师修炼
2020/07/17
6270
设计模式14之迭代器模式
直接遍历是集合直接参与的遍历的过程中,这里的遍历方法与集合对象的耦合性太高了。如果我们在直接遍历中操作集合,就出现操作异常。
Lvshen
2022/05/05
1440
设计模式14之迭代器模式
Java设计模式之迭代器模式
迭代器模式(Iterator),提供一种方法顺序访问一个聚合对象中的各种元素,而又不暴露该对象的内部表示。
BUG弄潮儿
2022/06/30
1960
Java设计模式之迭代器模式
【地铁上的设计模式】--行为型模式:迭代器模式
迭代器模式是一种行为型设计模式,它提供了一种遍历聚合对象中各个元素的方法,而不需要暴露该聚合对象的内部表示。这个模式分离了聚合对象的遍历行为,使得遍历算法能够与聚合对象分离开来,从而可以在不改变聚合对象的情况下定义新的遍历操作。迭代器模式由迭代器接口、具体迭代器类、聚合接口和具体聚合类等组成,其中迭代器接口定义了访问和遍历元素的方法,而聚合接口定义了创建迭代器的方法。迭代器模式的实现可以大大简化遍历聚合对象中元素的代码,同时也可以方便地新增不同类型的迭代器,从而为聚合对象提供不同的遍历行为。
喵叔
2023/05/09
3700
被用到炉火纯清的迭代器模式
Java中可以说已经把迭代器模式用到了极致,每一个集合类都关联了一个迭代器类Iterator。
BUG弄潮儿
2021/01/05
2940
通俗易懂设计模式解析——迭代器模式
  今天我们一起看看行为模式中的迭代器模式,迭代是重复反馈过程的活动,其目的通常是为了接近并到达所需的目标或结果。在系统开发中简单说可以理解成遍历。这种模式用于顺序访问集合对象的元素,不需要知道集合对象的底层或者内部表示。
小世界的野孩子
2019/10/10
4790
通俗易懂设计模式解析——迭代器模式
[设计模式]之九:迭代器模式
迭代器分离了集合对象的遍历行为,抽象出一个迭代器负责。这既可以不暴露内部结构,也让外部代码透明地访问集合内部数据
wOw
2018/09/18
2540
[设计模式]之九:迭代器模式
【设计模式】行为型模式-第 3 章第 4 讲【迭代器模式】
迭代器模式(Iterator Pattern)是 Java 和 .Net 编程环境中非常常用的设计模式。这种模式用于顺序访问集合对象的元素,不需要知道集合对象的底层表示。
跟着飞哥学编程
2022/11/16
1950
【设计模式】行为型模式-第 3 章第 4 讲【迭代器模式】
【愚公系列】2021年12月 二十三种设计模式(十六)-迭代器模式(Iterator Pattern)
设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。
愚公搬代码
2022/12/01
2020
【愚公系列】2021年12月 二十三种设计模式(十六)-迭代器模式(Iterator Pattern)
迭代器模式
主要思想和实现方式: 迭代器模式的主要思想是将数据的存储和遍历分离,使得客户端可以通过统一的接口遍历不同类型的集合,而不需要关心集合的具体实现。在C#中,迭代器模式可以通过实现IEnumerable接口和IEnumerator接口来实现。IEnumerable接口定义了一个方法GetEnumerator(),该方法返回一个实现了IEnumerator接口的迭代器对象。IEnumerator接口包含了MoveNext()方法,用于移动迭代器到集合的下一个元素,以及Current属性,用于获取当前元素的值。
JusterZhu
2023/10/24
1590
迭代器模式
迭代器模式
Iterator大家应该都很熟悉了,作为Java程序员的我们来说,遍历集合这也是我们刚开始学习Java知识。
敖丙
2021/07/02
4160
设计模式-迭代器模式
迭代器模式是数据访问遍历的一种行为模式。java中List、Set、Map 等都包含了迭代器。迭代器提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。迭代器模式的优点:
六个核弹
2022/12/23
1830
设计模式——迭代器模式
设计模式——迭代器模式
Java架构师必看
2021/05/14
3650
设计模式——迭代器模式
迭代器模式 迭代器模式
提供一种顺序访问集合的元素而不暴露其底层表示的方法。 ——《设计模式:可复用面向对象软件的基础》
mingmingcome
2021/12/09
6720
迭代器模式
    





        迭代器模式
C#设计模式18——迭代器模式的写法
迭代器模式是一种行为型设计模式,它允许客户端通过一种统一的方式遍历集合对象中的元素,而无需暴露集合对象的内部结构。
明志德道
2023/10/21
1470
小谈设计模式(21)—迭代器模式
主要对目前市面上常见的23种设计模式进行逐一分析和总结,希望有兴趣的小伙伴们可以看一下,会持续更新的。希望各位可以监督我,我们一起学习进步,加油,各位。
学编程的小程
2023/10/11
1740
小谈设计模式(21)—迭代器模式
相关推荐
「聊设计模式」之迭代器模式(Iterator)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验