注册 | 登录 忘记密码? 51cto首页 | 博客 | 论坛 | 招聘
热点文章 IT认证与技术学习-自己强..
 帮助

解读设计模式----迭代器模式(Iterator Pattern)


2008-06-01 15:36:33
版权声明:原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://beniao.blog.51cto.com/389148/79787
一、你在开发中使用过迭代吗?
     当你在使用JavaScript开发客户端应用的时候使用过for...in吗?
 1<script type="text/javascript">
 2var obj;
 3useForIn = function ()
 4{
 5   obj = (0,1,2,3,4,5,6,7,8,9);
 6   for(var o in obj)
 7   {
 8      document.write(o);
 9   }

10}

11</script>
 
      当你在.NET Frameworks上使用C#,VB.NET,等语言开发应用的时候使用过foreach....in吗?
 1class Program
 2{
 3    static void Main(string[] args)
 4    {
 5        List<int> list = new List<int>();
 6        //--------初始化集合-----------
 7        for (int i = 0; i < 10; i++)
 8        {
 9            list.Add(i);
10        }

11        //-------遍历集合--------------
12        foreach (int i in list)
13        {
14            Console.WriteLine(i);
15        }

16    }

17}

     如果你是一位Java发烧者,你在遍历集合的时候是使用什么方式呢?是Iterator?还是for?
 1import java.util.*;
 2public class UseForIn {
 3    public static void main(String[] args) {
 4        List<String> list = new ArrayList<String>();
 5        for (int i = 0; i < 10; i++{
 6            list.add("String:" + i);
 7        }

 8        //--------------使用Iterator遍历集合---------------
 9        Iterator it = list.iterator();
10        while(it.hasNext()){
11            System.out.println(it.next());
12        }

13        //------使用for.in(JDK 1.5以更高版本才能支持)-----
14        
15        for (String s : list ){
16            System.out.println(s);
17        }

18    }

19}
 
二、解说迭代模式
     我们先来看看迭代器模式的UML图(下图来至http://www.dofactory.com/)
        
迭代器模式(Iterator)
迭代器模式(Iterator),提供一种方法顺序访问一个集合对象中的各个元素,而不暴露该对象的内部表示。


        可以说,.NET Frameworks中的每一个集合对象,都应用了Iterator模式。一个聚集对象,而且不管这些对象是什么时候都需要遍历的时候,我们都应该使用迭代器模式。另外在我们需要为集合对象提供多种遍历方式的时候也可以考虑用迭代器模式。

        本来这个模式还是很有意思的,不过现今来看迭代器模式实用价格远不如学习价值大了。因为现在的高级编程语言如C#,Java等本身已经把这个模式做在语言中了。回到本文开始,我想你就能够明白我为什么在文章的开始部分就发起提问?就拿C#的foreach....in语言来说吧,他就是一个可以遍历所有的集合对象的工具,而且非常好用。

        另外还有像IEnumerable接口也是为迭代器模式而准备的,不管如何,学习一下GOF的迭代器模式的基本结构,还是很有学习价值的。研究历史是为了更好地迎接未来(这句话是Copy一本设计模式的书上,我一下忘了,如有知道的可以在下面留言告诉下)。

三、悟透foreach....in语句
        为了使用户更方便的遍历集合对象的所有元素,C#提供了foreach...in语句,该语句的实现正是通过IEnumerable的MoveNext()来完成遍历的。
        为了验证foreach....in语句与迭代器的关系,我们来定义一个实现逆序遍历集合的类ReverseList类,定义很简单,只需要继承ArrayList类,并重写GetEnumerator方法既可。
 1namespace DesignPattern.Iterator
 2{
 3    public class ReverseList:ArrayList
 4    {
 5        public override IEnumerator GetEnumerator()
 6        {
 7            return new ReverseListEnumerator(this);
 8        }

 9    }

10}

    其中,类ReverseListEnumerator实现了IEnumerator,它提供了逆序遍历的迭代器。定义如下:
 1using System;
 2using System.Collections.Generic;
 3using System.Text;
 4using System.Collections;
 5
 6namespace DesignPattern.Iterator
 7{
 8    public class ReverseListEnumerator:IEnumerator
 9    {
10        public ReverseListEnumerator(ArrayList list)
11        {
12            this.list = list;
13            this.index = list.Count;
14            this.CurrentElement = list;
15        }

16
17        private object CurrentElement;
18        private int index;
19        private ArrayList list;
20
21        public object Current
22        {
23            get 
24            {
25                object obj = this.CurrentElement;
26                if (obj != this.list)
27                {
28                    return obj;
29                }

30                if (this.index == -1)
31                {
32                    throw new Exception("索引超出下标范围!");
33                }

34            }

35        }

36
37        public bool MoveNext()
38        {
39            if (this.index > 0)
40            {
41                this.index--;
42                this.CurrentElement = this.list[this.index];
43                return true;
44            }

45            this.CurrentElement = this.list;
46            this.index = 0;
47            return false;
48        }

49
50        public void Reset()
51        {
52            this.CurrentElement = this.list;
53            this.index = this.list.Count;
54        }

55    }

56}

57

     我们来比较下使用ArrayList和自定义的ReverseList类通过foreach....in遍历后的结果:
 1using System;
 2using System.Collections.Generic;
 3using System.Text;
 4
 5namespace DesignPattern.Iterator
 6{
 7    class Program
 8    {
 9        static void Main(string[] args)
10        {
11            List<int> list = new List<int>();
12            ReverseList rlist = new ReverseList();
13            //--------初始化数据-----------------------
14            for (int i = 0; i < 10; i++)
15            {
16                list.Add(i);
17                rlist.Add(i);
18            }

19            //-----使用C#的foreach.in语句(顺序遍历类ArrayList)-------
20            foreach (int i in list)
21            {
22                Console.Write(i + " ");
23            }

24            Console.WriteLine();  //起换行作用
25
26            //--------使用自定义的逆序遍历类(ReverseList)--------------
27            foreach (int i in rlist)
28            {
29                Console.Write(i + " ");
30            }

31            Console.WriteLine();  //起换行作用
32        }

33    }

34}
 
运行结果如下:

四、现实生活中的迭代高手
     我想对于大多数(有一部分人自己有车,有部分人骑自行车或摩托车,有部分人步行)的人来说,每天都有这样的经历,早晨起床后一阵忙碌,忙完了就是准备上班了。来到了公交车站,XX分钟过去后,到上班点的公交来了,这时该做什么?上贝,不上你就等着上班迟到吧,哈哈。
     仔细观察售票员就会发现,每到一个站点,公交车都会停下上客或是下客,人多混杂(有的是买过票的,有的还没买过),我真佩服售票员的记忆,乘客随时都在上下,他总是能记住上了那些人,其中那些又是没有买票的。他可以从车头卖票到车尾,也可以从车尾到车头,也可以就在车门那站着售票,呵呵,这好象也迭代器有很大的联系。看看下面代码:
1public class 公交车:ArrayList
2{
3    
4}

     直接继承ArrayList,什么也不做,这时[公交车]也就拥有了ArrayList的公开属性和方法。下面是[乘客类];
 1using System;
 2using System.Collections.Generic;
 3using System.Text;
 4
 5namespace DesignPattern.Iterator
 6{
 7    public class 乘客
 8    {
 9