栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > .Net

设计模式——迭代器模式

.Net 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

设计模式——迭代器模式

一:介绍

迭代器模式提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示
对于一个集合类,必然涉及到添加删除操作,同时也需要支持遍历元素的操作,虽然我们也可以把遍历对象的操作也放在集合类中,但这就违背了单一职责原则,我们要尽可能地分离这些职责,用不同的类去承担不同的职责,迭代器模式就是将存储数据和遍历数据的责任进行了分离


二:适用场景

——访问一个聚合对象中的各个元素


三:迭代器模式的实现

迭代器模式的实现包含四个部分
——抽象迭代器Iterator:定义了访问和遍历元素的接口,需要在具体迭代器类中实现这些方法
——具体迭代器TestIterator:实现抽象迭代器接口,记录遍历中的当前位置
——抽象聚合类IteratorAggregate:创建相应的迭代器对象的接口。带有一个GetIterator()方法用于创建迭代器对象
——具体聚合类Test:实现集合类并实现GetIterator()方法

using System;
using System.Collections;
using System.Collections.Generic;

class MainClass
{
    static void Main()
    {
        int[] numArray = { 1, 2, 3, 4, 5 };
        Test test = new Test(numArray);

        Iterator it = test.GetIterator();
        while (it.CanNext())
        {
            Console.WriteLine(it.CurObj);
            it.Next();
        }
    }
}

public class Test : IteratorAggregate
{
    public int[] numArray;

    public Test(int[] numArray)
    {
        this.numArray = numArray;
    }

    public Iterator GetIterator()
    {
        return new TestIterator(this);
    }
}

public class TestIterator : Iterator
{
    Test test;
    int index;
    public object CurObj
    {
        get
        {
            if (index < test.numArray.Length)
            {
                return test.numArray[index];
            }
            throw new InvalidOperationException();
        }
    } 

    public TestIterator(Test test)
    {
        this.test = test;
        index = 0;
    }

    public bool CanNext()
    {
        if (index < test.numArray.Length)
        {
            return true;
        }
        return false;
    }

    public void Next()
    {
        if (index < test.numArray.Length)
        {
            index++;
        }
    }

    public void Reset()
    {
        index = 0;
        test = null;
    }
}

public interface Iterator
{
    object CurObj { get; }
    bool CanNext();
    void Next();
    void Reset();
}

public interface IteratorAggregate
{
    Iterator GetIterator();
}

执行顺序
1.调用对象的GetIterator接口,创建迭代器
2.循环判断是否还有元素,直到返回值为false
3.输出元素
4.得到下一个元素下标


四:.NET中的迭代器

在.NET中,抽象聚合类和抽象迭代器已经被定义好,分别是IEnumerable和IEnumerator接口
通过上面的迭代器模式的实现可知,一个类之所以能够被foreach迭代,是因为实现了IEnumerable接口

现在我们就可以很好的理解foreach内部执行原理了,foreach其实只是一个语法糖,编译器内部是使用while循环来实现的
 

.NET中自定义迭代器:

using System;
using System.Collections;

class MainClass
{
    static void Main(string[] args)
    {
        int[] numArray = { 1, 2, 3, 4, 5 };
        Test test = new Test(numArray);

        foreach (var temp in test)
        {
            Console.WriteLine(temp);
        }
    }
}

public class Test : IEnumerable
{
    public int[] numArray;

    public Test(int[] numArray)
    {
        this.numArray = numArray;
    }

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

public class MyEnumerator : IEnumerator
{
    Test curObj;
    int index;

    public MyEnumerator(Test curObj)
    {
        this.curObj = curObj;
        index = -1;
    }

    public object Current
    {
        get
        {
            if (index == -1 && index == curObj.numArray.Length)
            {
                throw new InvalidOperationException();
            }
            return curObj.numArray[index];
        }
    }

    public bool MoveNext()
    {
        if (index <= curObj.numArray.Length)
        {
            index++;
        }
        return index < curObj.numArray.Length;
    }

    public void Reset()
    {
        index = -1;
    }
}

.NET中迭代器的内部执行顺序:
1.首先初始化状态
2.调用MoveNext得到下一个数据的下标
3.调用Current属性得到返回的值
4.当MoveNext方法返回false时迭代结束 

目前.NET提供了一种更简便的方法:yield return语句,大大的减少了代码量,yield return告诉编译器这不是一个普通方法而是一个需要执行的迭代块,执行时编译器内部会为我们自动创建并实现了上面IEnumerator接口类

using System;
using System.Collections;

class MainClass
{
    static void Main(string[] args)
    {
        int[] numArray = { 1, 2, 3, 4, 5 };
        Test test = new Test(numArray);

        foreach (var temp in test)
        {
            Console.WriteLine(temp);
        }
    }
}

public class Test : IEnumerable
{
    public int[] numArray;

    public Test(int[] numArray)
    {
        this.numArray = numArray;
    }

    public IEnumerator GetEnumerator()
    {
        for (int i = 0; i < numArray.Length; i++)
        {
            yield return numArray[i];
        }
    }
}

五:迭代器的延迟计算特性

由迭代器的内部执行顺序可知,当调用MoveNext方法时迭代器才会执行,所以迭代器是延迟计算的

using System;
using System.Collections;
using System.Collections.Generic;

class MainClass
{
    static void Main(string[] args)
    {
        WithIterator();
        Console.WriteLine("=====");
        WithNoIterator();
        Console.WriteLine("=====");
        foreach (var item in WithIterator())
        {
            Console.WriteLine("使用foreach输出,当前i的值为:" + item);
        }
    }

    public static IEnumerable WithNoIterator()
    {
        List list = new List();
        for (int i = 0; i < 5; i++)
        {
            Console.WriteLine("当前i的值为:{0}", i);
            list.Add(i);
        }

        return list;
    }

    public static IEnumerable WithIterator()
    {
        for (int i = 0; i < 5; i++)
        {
            Console.WriteLine("当前i的值为:{0}", i);
            yield return i;
        }
    }
}

六:其他

例如我们要获取到集合中是否有元素,通常使用Count(),但使用Count()获得集合元素数量必然要迭代完所有元素,时间复杂度为O(n),而使用MoveNext只需要迭代一次就可以,时间复杂度为O(1),Linq为我们提供了扩展方法:Any()

bool b=list.Count() > 0;
bool b=list.GetEnumerator().MoveNext();
bool b = list.Any();

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1023400.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号