zoukankan      html  css  js  c++  java
  • 听webcast的行为型模式篇迭代器模式(Iterator Pattern) 记录

    < DOCTYPE html PUBLIC -WCDTD XHTML StrictEN httpwwwworgTRxhtmlDTDxhtml-strictdtd>

    dotnet或java里面这种设计模式已经集成在foreach里面了,同时想到我们应该用面向接口编程,类太脆弱易变,只能is a,而接口是稳定的是became,as.下面是听webcast讲师的记录.

            概述

            在面向对象的软件设计中,我们经常会遇到一类集合对象,这类集合对象的内部结构可能有着各种各样的实现,但是归结起来,无非有两点是需要我们去关心的:一是集合内部的数据存储结构,二是遍历集合内部的数据。面向对象设计原则中有一条是类的单一职责原则,所以我们要尽可能的去分解这些职责,用不同的类去承担不同的职责。Iterator模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可让外部代码透明的访问集合内部的数据。

        意图

            提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。[GOF 《设计模式》]

        结构图

            Iterator模式结构图如下:
    听webcast的行为型模式篇-迭代器模式(Iterator Pattern) 记录 - netcorner - netcorner的博客
    图1 Iterator模式结构图

        生活中的例子

            迭代器提供一种方法顺序访问一个集合对象中各个元素,而又不需要暴露该对象的内部表示。在早期的电视机中,一个拨盘用来改变频道。当改变频道时,需要手工转动拨盘移过每一个频道,而不论这个频道是否有信号。现在的电视机,使用[后一个]和[前一个]按钮。当按下[后一个]按钮时,将切换到下一个预置的频道。想象一下在陌生的城市中的旅店中看电视。当改变频道时,重要的不是几频道,而是节目内容。如果对一个频道的节目不感兴趣,那么可以换下一个频道,而不需要知道它是几频道。
    听webcast的行为型模式篇-迭代器模式(Iterator Pattern) 记录 - netcorner - netcorner的博客
    图2 使用选频器做例子的Iterator模式对象图

        Iterator模式解说

        在面向对象的软件设计中,我们经常会遇到一类集合对象,这类集合对象的内部结构可能有着各种各样的实现,但是归结起来,无非有两点是需要我们去关心的:一是集合内部的数据存储结构,二是遍历集合内部的数据。面向对象设计原则中有一条是类的单一职责原则,所以我们要尽可能的去分解这些职责,用不同的类去承担不同的职责。Iterator模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可让外部代码透明的访问集合内部的数据。下面看一个简单的示意性例子,类结构图如下:
    听webcast的行为型模式篇-迭代器模式(Iterator Pattern) 记录 - netcorner - netcorner的博客
    图3 示例代码结构图

            首先有一个抽象的聚集,所谓的聚集就是就是数据的集合,可以循环去访问它。它只有一个方法GetIterator()让子类去实现,用来获得一个迭代器对象。

    /// <summary>/// 抽象聚集/// </summary> public interface IList{IIterator GetIterator();}

            抽象的迭代器,它是用来访问聚集的类,封装了一些方法,用来把聚集中的数据按顺序读取出来。通常会有MoveNext()、CurrentItem()、Fisrt()、Next()等几个方法让子类去实现。

    /// <summary>/// 抽象迭代器/// </summary> public interface IIterator{bool MoveNext();Object CurrentItem();void First();void Next();}

            具体的聚集,它实现了抽象聚集中的唯一的方法,同时在里面保存了一组数据,这里我们加上Length属性和GetElement()方法是为了便于访问聚集中的数据。

    /// <summary>/// 具体聚集/// </summary>public class ConcreteList : IList{int[] list;public ConcreteList(){list = new int[] { 1,2,3,4,5};}public IIterator GetIterator(){return new ConcreteIterator(this);}public int Length{get { return list.Length; }}public int GetElement(int index){return list[index];}}

            具体迭代器,实现了抽象迭代器中的四个方法,在它的构造函数中需要接受一个具体聚集类型的参数,在这里面我们可以根据实际的情况去编写不同的迭代方式。

    /// <summary>/// 具体迭代器/// </summary> public class ConcreteIterator : IIterator{private ConcreteList list;private int index;public ConcreteIterator(ConcreteList list){this.list = list;index = 0;}public bool MoveNext(){if (index < list.Length)return true;elsereturn false;}public Object CurrentItem(){return list.GetElement(index) ;}public void First(){index = 0;}public void Next(){if (index < list.Length){index++;}}}

            简单的客户端程序调用:

    /// <summary>/// 客户端程序/// </summary> class Program{static void Main(string[] args){IIterator iterator;IList list = new ConcreteList();iterator = list.GetIterator();while (iterator.MoveNext()){int i = (int)iterator.CurrentItem();Console.WriteLine(i.ToString());iterator.Next();}Console.Read();}}

            一个简单的迭代器示例就结束了,这里我们并没有利用任何的.NET特性,在C#中,实现Iterator模式已经不需要这么麻烦了,已经C#语言本身就有一些特定的实现,下面会说到。

        .NET中的Iterator模式

        在.NET下实现Iterator模式,对于聚集接口和迭代器接口已经存在了,其中IEnumerator扮演的就是迭代器的角色,它的实现如下:

    public interface IEumerator{object Current{get;}bool MoveNext();void Reset();}

            属性Current返回当前集合中的元素,Reset()方法恢复初始化指向的位置,MoveNext()方法返回值true表示迭代器成功前进到集合中的下一个元素,返回值false表示已经位于集合的末尾。能够提供元素遍历的集合对象,在.Net中都实现了IEnumerator接口。

            IEnumerable则扮演的就是抽象聚集的角色,只有一个GetEnumerator()方法,如果集合对象需要具备跌代遍历的功能,就必须实现该接口。

    public interface IEnumerable{IEumerator GetEnumerator();}

            下面看一个在.NET1.1下的迭代器例子,Person类是一个可枚举的类。PersonsEnumerator类是一个枚举器类。这个例子来自于http://www.theserverside.net/,被我简单的改造了一下。

    public class Persons : IEnumerable{public string[] m_Names;public Persons(params string[] Names){m_Names = new string[Names.Length];Names.CopyTo(m_Names,0);}private string this[int index]{get{return m_Names[index];}set{m_Names[index] = value;}}public IEnumerator GetEnumerator(){return new PersonsEnumerator(this);}}public class PersonsEnumerator : IEnumerator{private int index = -1;private Persons P;public PersonsEnumerator(Persons P){this.P = P;}public bool MoveNext(){index++;return index < P.m_Names.Length;}public void Reset(){index = -1;}public object Current{get{return P.m_Names[index];}}}

            来看客户端代码的调用:

    class Program{static void Main(string[] args){Persons arrPersons = new Persons("Michel","Christine","Mathieu","Julien");foreach (string s in arrPersons){Console.WriteLine(s);}Console.ReadLine();}}

            程序将输出:

            Michel
            Christine
            Mathieu
            Julien

            现在我们分析编译器在执行foreach语句时到底做了什么,它执行的代码大致如下:

    class Program{static void Main(string[] args){Persons arrPersons = new Persons("Michel","Christine","Mathieu","Julien");IEnumerator e = arrPersons.GetEnumerator();while (e.MoveNext()){Console.WriteLine((string)e.Current);}Console.ReadLine();}}

            可以看到这段代码跟我们最前面提到的示例代码非常的相似。同时在这个例子中,我们把大部分的精力都花在了实现迭代器和可迭代的类上面,在.NET2.0下面,由于有了yield return关键字,实现起来将更加的简单优雅。下面我们把刚才的例子在2.0下重新实现一遍:

    public class Persons : IEnumerable{string[] m_Names;public Persons(params string[] Names){m_Names = new string[Names.Length];Names.CopyTo(m_Names,0);}public IEnumerator GetEnumerator(){foreach (string s in m_Names){yield return s;}}}class Program{static void Main(string[] args){Persons arrPersons = new Persons("Michel","Christine","Mathieu","Julien");foreach (string s in arrPersons){Console.WriteLine(s);}Console.ReadLine();}}

            程序将输出:

            Michel
            Christine
            Mathieu
            Julien

            实现相同的功能,由于有了yield return关键字,变得非常的简单。好了,关于.NET中的Iterator模式就说这么多了,更详细的内容大家可以参考相关的资料。

        效果及实现要点

            1 .迭代抽象:访问一个聚合对象的内容而无需暴露它的内部表示。
            2.迭代多态:为遍历不同的集合结构提供一个统一的接口,从而支持同样的算法在不同的集合结构上进行操作。
            3.迭代器的健壮性考虑:遍历的同时更改迭代器所在的集合结构,会导致问题。

        适用性

            1.访问一个聚合对象的内容而无需暴露它的内部表示。
            2.支持对聚合对象的多种遍历。
            3.为遍历不同的聚合结构提供一个统一的接口(即, 支持多态迭代)。

        总结

            Iterator模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可让外部代码透明的访问集合内部的数据。

  • 相关阅读:
    关于求 p_i != i and p_i != i+1 的方案数的思考过程
    poj 3041 Asteroids 二分图最小覆盖点
    poj 1325 Machine Schedule 最小顶点覆盖
    poj 1011 Sticks 减枝搜索
    poj 1469 COURSES 最大匹配
    zoj 1516 Uncle Tom's Inherited Land 最大独立边集合(最大匹配)
    Path Cover (路径覆盖)
    hdu 3530 SubSequence TwoPoint单调队列维护最值
    zoj 1654 Place the Rebots 最大独立集转换成二分图最大独立边(最大匹配)
    poj 1466 Girls and Boys 二分图最大独立子集
  • 原文地址:https://www.cnblogs.com/netcorner/p/2912296.html
Copyright © 2011-2022 走看看