模式十一:迭代器模式

        11.1迭代器模式定义:

迭代器模式提供一种模式顺序访问一个集合对象中的各个元素,而又不暴露其内部的表示。  

11.2迭代器模式UML类图:

 

11.3应用场景:

 由于每个集合对象本身不一样,所以当我们对不同类型的集合进行遍历时,由于必须暴露其内部表示,所写的遍历语句(for/foreach)也是不能通用的。而如果我们对需要用到的集合创建迭代器,由于对迭代器的遍历语句是相同的,则我们可以实现遍历语句的通用。另外,拥有了迭代器也就意味着我们对集合的实现是完全不知道的,以后一旦我们需要改变集合的实现,例如从数组改成ArrayList,客户端的代码是不需要做任何变动的,客户甚至不知道所遍历的集合发生了改变。

 

11.4迭代器模式分析与实现(c#描述):

//我们使用自己定义的迭代器接口示例。

    namespace CustomIterator

    {

        //我们自己定义的迭代器接口

        public interface IIterator

        {

            bool HasNext();//判断是否已到集合尾。

            object Next();//该方法既返回当前值,同时也将集合当前指针移动到下一条记录。

        }

 

 

        //整型数组迭代器,用于对整型数组的遍历,这里应该也可以利用范型创建范型数组迭代器。

        public class IteratorForArray : IIterator

        {

            private int[] iarr_Array;

            private int iint_Position = 0;

 

            public IteratorForArray(int[] aarr_Array)

            {

                this.iarr_Array = aarr_Array;

            }

 

            public bool HasNext()

            {

                if (this.iint_Position >= this.iarr_Array.Length)

                {

                    return false;

                }

                else return true;

            }

 

            public object Next()

            {

                return this.iarr_Array[this.iint_Position++];

            }

        }

 

        //ArrayList迭代器,用于对ArrayList的遍历。

        public class IteratorForArrayList : IIterator

        {

            private ArrayList ial_ArrayList;

            private int iint_Position = 0;

 

            public IteratorForArrayList(ArrayList aal_Array)

            {

                this.ial_ArrayList = aal_Array;

            }

 

            public bool HasNext()

            {

                if (this.iint_Position >= this.ial_ArrayList.Count)

                {

                    return false;

                }

                else return true;

            }

 

            public object Next()

            {

                return this.ial_ArrayList[this.iint_Position++];

            }

        }

 

 

        //集合接口:一旦某一个类实现了集合接口IAggregate(IEnumerable)就表明该类中必定有某一集合需要用到迭代器,进一步:即可以对该类进行遍历。

        public interface IAggregate

        {

            IIterator CreateIterator();//创建一个迭代器。

        }

 

        //持有某一集合的具体实现类

        public class ShopKeeperA : IAggregate

        {

            private int[] iarr_SalesAmount = new int[] { 1, 4, 2, 5 };//为了简单起见,我们将店长每天的销售记录写在这里。

            public IIterator CreateIterator()

            {

                return new IteratorForArray(this.iarr_SalesAmount);//由于A店长的销售记录是存储在整型数组中,所以这里用整型数组迭代器。

            }

        }

 

 

        public class ShopKeeperB : IAggregate

        {

            private ArrayList ial_SalesAmount = new ArrayList() { 2, 3, 2, 1 };

            public IIterator CreateIterator()

            {

                return new IteratorForArrayList(this.ial_SalesAmount);//由于B店长的销售记录是存储在ArrayList中,所以这里用ArrayList迭代器。

            }

        }

 

 

        //调用类

        public class IIterator_Test

        {

            public static void Do()

            {

                //下面对A店长拥有的集合进行遍历,输出1,4,2,5

                IAggregate iAggregate = new ShopKeeperA();//注意:我们并不是对ShopKeeperA进行遍历,而是对ShopKeeperA中的集合进行遍历。

                IIterator iIterator = iAggregate.CreateIterator();//ShopKeeperA创建了迭代器,因此可以利用迭代器对ShopKeeperA中的集合进行遍历了。

                while (iIterator.HasNext())

                {

                    int lint_Temp = (int)iIterator.Next();

                    Console.WriteLine(lint_Temp);

                }

 

                //下面对B店长拥有的集合进行遍历,输出2,3,2,1

                iAggregate = new ShopKeeperB();

                iIterator = iAggregate.CreateIterator();//ShopKeeperB创建了迭代器,因此可以利用迭代器对ShopKeeperB中的集合进行遍历了。

                while (iIterator.HasNext())

                {

                    int lint_Temp = (int)iIterator.Next();

                    Console.WriteLine(lint_Temp);

                }

 

                //回到迭代器模式的定义:迭代器模式提供一种模式顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。

                //这里我们遍历了ShopKeeperAShopKeeperB集合中的元素,却不知道该集合是用什么表示的(即不知道是集合用数组还是用ArrayList存储)

                //如果我们以后改变集合的存储方式,客户端的代码是不需要做任何变动的,不是吗?

            }

        }

    }

 

    //使用C#中现有的迭代器接口示例。

    namespace IteratorInCSharp {              

        //上例中我们定义的IAggregateC#中对应为IEnumerable

        //上例中我们定义的IIteratorC#中对应为IEnumerator(迭代器接口)        

        public class ShopKeeperA : IEnumerable

        {

            private int[] iarr_SalesAmount = new int[] { 1, 4, 2, 5 };

 

            public IEnumerator GetEnumerator()

            {

                return this.iarr_SalesAmount.GetEnumerator();//C#已经为我们定义了数组的迭代器,所以我们不需要自己写了,直接调用即可。

            }

        }

 

        public class ShopKeeperB : IEnumerable

        {

            private ArrayList ial_SalesAmount = new ArrayList() { 2, 3, 2, 1 };

            public IEnumerator GetEnumerator()

            {

                return this.ial_SalesAmount.GetEnumerator();//C#已经为我们定义了ArrayList的迭代器,所以我们不需要自己写了,直接调用即可。

            }

        }

 

  

 

        //调用类

        public class IIterator_Test

        {

            public static void Do()

            {

                //下面对A店长拥有的集合进行遍历,输出1,4,2,5

                IEnumerable iEnumerable = new ShopKeeperA();//注意:我们并不是对ShopKeeperA进行遍历,而是对ShopKeeperA中的集合进行遍历。

                IEnumerator iEnumerator = iEnumerable.GetEnumerator();//ShopKeeperA创建了迭代器,因此可以利用迭代器对ShopKeeperA中的集合进行遍历了。

                while (iEnumerator.MoveNext())

                {

                    int lint_Temp = (int)iEnumerator.Current;

                    Console.WriteLine(lint_Temp);

                }

//上面这段代码实际上就是foreach语句,foreach是上面代码的一种语法上的简写。

                //下面对B店长拥有的集合进行遍历,输出2,3,2,1

                iEnumerable = new ShopKeeperB();

                iEnumerator = iEnumerable.GetEnumerator();//ShopKeeperA创建了迭代器,因此可以利用迭代器对ShopKeeperA中的集合进行遍历了。

                while (iEnumerator.MoveNext())

                {

                    int lint_Temp = (int)iEnumerator.Current;

                    Console.WriteLine(lint_Temp);

                }

 

                iEnumerator.Reset();//我们将迭代器复位,则该集合又可重新遍历了,再次输出2,3,2,1

                while (iEnumerator.MoveNext())

                {

                    int lint_Temp = (int)iEnumerator.Current;

                    Console.WriteLine(lint_Temp);

                }

 

                //另外C#中的foreach语句就是对实现了IEnumerable接口的类进行遍历,既然这里我们ShopKeeperA/B实现了IEnumerable接口,那么我们就可以利用foreach语句对其进行遍历

                foreach (int lint_Temp in iEnumerable)//这里foreach语句实现上就是调用类的迭代器对集合进行遍历,由于我们迭代器接口(IEnumerator)中并没有对集合元素进行更改的方法,这也就决定了foreach语句不可能对集合元素进行“写”操作。

                {

                    Console.WriteLine(lint_Temp);

                }

               

            }

        }

   

 }

 

至此,迭代器模式完毕。

 

迭代器模式把元素之间遍历的任务交给了迭代器来完成,而不是集合对象。这不仅让集合的接口和实现变得更加简洁,也可以让聚合更加专注在它所应该专注的事情上,即:管理对象集合,而不去理会遍历的事情。这也就是迭代器模式为我们带来的一个重要设计原则:设计原则:一个类应该只有一个引起变化的原因。因为类的每个责任都有改变的的潜在区域。超过一个责任,意味着超过一个改变的区域。这个原则告诉我们:应该让每个类保持单一责任。这里如果我们让集合类(数组,ArrayList)一方面管理自身的集合对象,又要担负例如遍历的责任时,我们就相当于给了这个类2个变化的原因。如果集合改变的话,这个类也必须改变,如果这个集合的遍历方式改变的话,这个类还是要改变。所以我们应该让一个类应该只有一个引起变化的原因,而不是多个。

 另外注意一下:迭代器只是对集合遍历进行遍历,它并不假设集合元素之间有任何顺序关系。例如我们甚至可以针对散列表写一个迭代器。

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值