且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

【愚公系列】2021年12月 二十三种设计模式(十六)-迭代器模式(Iterator Pattern)

更新时间:2022-05-13 16:41:02

文章目录

前言

一、迭代器模式(Iterator Pattern)

二、使用步骤

角色

示例

传统迭代器实现

yield return迭代器实现

总结

优点

缺点

使用场景

前言

设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。


提示:以下是本篇文章正文内容,下面案例可供参考


一、迭代器模式(Iterator Pattern)

迭代器模式属于行为型模式,它提供一种方法顺序访问一个聚合对象中的各种元素,而又不暴露该对象的内部表示,这样既可以做到不暴露集合的内部结构,又可让外部代码透明地访问集合内部的数据。


二、使用步骤

角色

1、迭代器(Iterator)


迭代器角色负责定义访问和遍历元素的接口;


2、具体迭代器(Concrete Iteraror)


具体迭代器角色实现了迭代器接口,并需要记录遍历中的当前位置;


3、聚合(Aggregate)


聚合角色负责定义获得迭代器角色的接口;


4、具体聚合(Concrete Aggregate)


具体聚合角色实现聚合角色接口。


示例

【愚公系列】2021年12月 二十三种设计模式(十六)-迭代器模式(Iterator Pattern)

命名空间IteratorPattern中包含Person基类、People类、PelpleEnum类,另外包含一个苹果手机ApplePhone类,和BestEnum类。Person示例来自微软官方的 IEnumerable接口 介绍页面,BestEnum则使用.Net 2.0中的yield return关键字创建苹果手机信息序列。

namespace IteratorPattern

传统迭代器实现

public class Person {

    public string FirstName { get; set; }
    public string LastName { get; set; }

    public Person(string firstName, string lastName) {
        this.FirstName = firstName;
        this.LastName = lastName;
    }

}

Person类,包含First Name和Last Name。

public class People : IEnumerable {

    private Person[] _people = null;

    public People(Person[] pArray) {
        _people = new Person[pArray.Length];

        for (int i = 0; i < pArray.Length; i++) {
            _people[i] = pArray[i];
        }
    }

    public IEnumerator GetEnumerator() {
        return new PeopleEnum(_people);
    }

}

People类,实现IEnumerable接口。

public class PeopleEnum : IEnumerator {

    private Person[] _people = null;

    private int _cursor = -1;

    public PeopleEnum(Person[] list) {
        _people = list;
    }

    public bool MoveNext() {
        _cursor++;
        return (_cursor < _people.Length);
    }

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

    public object Current {
        get {
            try {
                return _people[_cursor];
            }
            catch (IndexOutOfRangeException) {
                throw new InvalidOperationException();
            }
        }
    }

}

PeopleEnum类,实现IEnumerator接口。

yield return迭代器实现

yield关键字向编译器指示它所在的方法是迭代器块,yield return返回一个迭代器的状态机。

public class ApplePhone {

    public string PhoneName { get; set; }

    public DateTime PublishedDate { get; set; }

}

ApplePhone类,包含手机名称和发布日期。

public class BestEnum {

    public static IEnumerable<ApplePhone> GetIPhones() {
        yield return new ApplePhone {
            PhoneName = "IPhone",
            PublishedDate = new DateTime(2007, 1, 9)
        };
        yield return new ApplePhone {
            PhoneName = "IPhone 3G",
            PublishedDate = new DateTime(2008, 6, 10)
        };
        yield return new ApplePhone {
            PhoneName = "IPhone 3GS",
            PublishedDate = new DateTime(2009, 6, 9)
        };
        yield return new ApplePhone {
            PhoneName = "IPhone 4",
            PublishedDate = new DateTime(2010, 6, 8)
        };
        //部分代码已省略
    }

}

BestEnum类,包含GetIPhones方法返回苹果手机信息的序列。

public class Program {

    protected const string LINE_BREAK =
        "---------------------------------------------";

    public static void Main(string[] args) {
        var peopleArray = new Person[]
        {
            new Person("John", "Smith"),
            new Person("Jim", "Johnson"),
            new Person("Sue", "Rabon")
        };

        var peopleList = new People(peopleArray);
        foreach(Person p in peopleList)
            Console.WriteLine(p.FirstName + " " + p.LastName);

        Console.WriteLine(LINE_BREAK);

        var iterator = peopleList.GetEnumerator();
        while(iterator.MoveNext()) {
            var person = iterator.Current as Person;
            Console.WriteLine(person.FirstName + " " + person.LastName);
        }

        Console.WriteLine(LINE_BREAK);

        foreach(var phone in BestEnum.GetIPhones()) {
            Console.WriteLine("[" + phone.PhoneName + "] was released in " +
                              phone.PublishedDate.ToString("yyyy-MM-dd") + "!");
        }

        Console.WriteLine(LINE_BREAK);

        Console.ReadKey();
    }

}

以上是调用方的代码,以下是这个案例的输出结果:

John Smith
Jim Johnson
Sue Rabon
---------------------------------------------
John Smith
Jim Johnson
Sue Rabon
---------------------------------------------
[IPhone] was released in 2007-01-09!
[IPhone 3G] was released in 2008-06-10!
[IPhone 3GS] was released in 2009-06-09!
[IPhone 4] was released in 2010-06-08!
[IPhone 4s] was released in 2011-10-04!
[IPhone 5] was released in 2012-09-13!
[IPhone 5S] was released in 2013-09-10!
[IPhone 5C] was released in 2013-09-10!
[IPhone 6] was released in 2014-09-10!
[IPhone 6 Plus] was released in 2014-09-10!
[IPhone 6s] was released in 2015-09-10!
[IPhone 6s Plus] was released in 2015-09-10!
[IPhone 7] was released in 2016-09-08!
[IPhone 7 Plus] was released in 2016-09-08!
[IPhone 8] was released in 2017-09-13!
[IPhone 8 Plus] was released in 2017-09-13!
[IPhone X] was released in 2017-09-13!
---------------------------------------------

总结

优点

1、迭代器模式使得访问一个聚合对象的内容而无需暴露它的内部表示,即迭代抽象;

2、迭代器模式为遍历不同的集合结构提供了一个统一的接口,从而支持同样的算法在不同的集合结构上进行操作。


缺点

1、迭代器模式在遍历的同时更改迭代器所在的集合结构会导致出现异常。所以使用foreach语句只能在对集合进行遍历,不能在遍历的同时更改集合中的元素。


使用场景

1、系统需要访问一个聚合对象的内容而无需暴露它的内部表示;

2、系统需要支持对聚合对象的多种遍历;

3、系统需要为不同的聚合结构提供一个统一的接口。