日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

.Net中的設(shè)計(jì)模式——Iterator模式

 ljjzlm 2006-08-04

.Net中的設(shè)計(jì)模式——Iterator模式

Filed under: .Net Framework, Design & Pattern — bruce zhang @ 1:43 pm

一、模式概述

在面向?qū)ο笤O(shè)計(jì)時(shí),我們常常需要辨認(rèn)對(duì)象的職責(zé)。理想的狀態(tài)下,我們希望自己建立的對(duì)象只具有一個(gè)職責(zé)。對(duì)象的責(zé)任越少,則該對(duì)象的穩(wěn)定性就越好,受到的約束也就越少。職責(zé)分離,可以最大限度地減少彼此之間的耦合程度,從而建立一個(gè)松散耦合的對(duì)象網(wǎng)絡(luò)。

職責(zé)分離的要點(diǎn)是對(duì)被分離的職責(zé)進(jìn)行封裝,并以抽象的方式建立起彼此之間的關(guān)系。在C#中,我們往往將這些可能變化的對(duì)象抽象為接口和抽象類(lèi),從而將原來(lái)的具體依賴(lài)改變?yōu)槌橄笠蕾?lài)。對(duì)象不再受制于具體的實(shí)現(xiàn)細(xì)節(jié),這就代表他們是可被替換的。

要在設(shè)計(jì)上做到這一點(diǎn),首先就要學(xué)會(huì)分辨職責(zé),學(xué)會(huì)分辨哪些職責(zé)是對(duì)象中可變的。以集合對(duì)象為例,集合是一個(gè)管理和組織數(shù)據(jù)對(duì)象的數(shù)據(jù)結(jié)構(gòu)。這就表明集合首先應(yīng)具備一個(gè)基本屬性,就是集合能夠存儲(chǔ)數(shù)據(jù)。這其中包含存儲(chǔ)數(shù)據(jù)的類(lèi)型、存儲(chǔ)空間的大小、存儲(chǔ)空間的分配、以及存儲(chǔ)的方式和順序。不具備這些特點(diǎn),則該對(duì)象就不成其為集合對(duì)象。也就是說(shuō),上述這些屬性是集合對(duì)象與身俱來(lái)的,是其密不可分的職責(zé)。然而,集合對(duì)象除了能夠存儲(chǔ)數(shù)據(jù)外,還必須提供訪問(wèn)其內(nèi)部數(shù)據(jù)的行為方式,這是一種遍歷機(jī)制。同時(shí)這種遍歷方式,或會(huì)根據(jù)不同的情形提供不同的實(shí)現(xiàn),如順序遍歷,逆序遍歷,或是二叉樹(shù)結(jié)構(gòu)的中序、前序、后序遍歷。

現(xiàn)在我們已經(jīng)分辨出集合對(duì)象擁有的兩個(gè)職責(zé):一是存儲(chǔ)內(nèi)部數(shù)據(jù);二是遍歷內(nèi)部數(shù)據(jù)。從依賴(lài)性來(lái)看,前者為集合對(duì)象的根本屬性,屬于一生俱生,一亡俱亡的關(guān)系;而后者既是可變化的,又是可分離的。因此,我們將遍歷行為分離出來(lái),抽象為一個(gè)迭代器,專(zhuān)門(mén)提供遍歷集合內(nèi)部數(shù)據(jù)對(duì)象的行為。這就是Iterator模式的本質(zhì)。

如一個(gè)列表對(duì)象List,它提供了遍歷列表各元素的能力,這種遍歷的行為可能包含兩種:順序和逆序遍歷。對(duì)于一般的List對(duì)象而言,采用順序遍歷的方式;而對(duì)于特定的List對(duì)象,如ReverseList,則按照逆序遍歷的方式訪問(wèn)其內(nèi)部數(shù)據(jù)。如果不將存儲(chǔ)數(shù)據(jù)和訪問(wèn)數(shù)據(jù)的職責(zé)分離,為實(shí)現(xiàn)ReverseList類(lèi),就需要重寫(xiě)其父類(lèi)List中所有用于遍歷數(shù)據(jù)的方法?,F(xiàn)在我們采用Iterator模式,在List對(duì)象中分離出迭代器IListIterator,那就只需要為這個(gè)繼承自List對(duì)象的ReverseList對(duì)象,提供逆序迭代器ReverseListIterator就可以了,如下面的類(lèi)圖所示:

iterator1.GIF

代碼如下:
public interface IListIterator
{
 void First();
 void Last();
 bool MoveNext();
}
public class SequenceListIterator:IListIterator
{
 private List list = null;
 private int index;
 public SequenceListIterator(List list)
 {
      index = -1;
      this.list = list;
 }
 public void First()
 {
      index = 0;
 }
 public void Last()
 {
      index = list.Count;
 }
 public bool MoveNext()
 {
      index ++;
      return list.Count > index;
 }
}
public class ReverseListIterator:IListIterator
{
 private List list = null;
 private int index;
 public ReverseListIterator(List list)
 {
      index = list.Count;
      this.list = list;
 }
 public void First()
 {
      index = list.Count - 1;
 }
 public void Last()
 {
      index = 0;
 }
 public bool MoveNext()
 {
      index –;
      return index >= 0;
 }
}
public class List
{
 public virtual IListIterator CreateIterator()
 {
      return new SequenceListIterator(this);
 }
}
public class ReverseList:List
{
 public override IListIterator CreateIterator()
 {
      return new ReverseListIterator(this);
 }
}

我們看到,List類(lèi)通過(guò)方法CreateIterator(),創(chuàng)建了SequenceListIterator對(duì)象,使得List集合對(duì)象能夠用順序迭代的方式遍歷內(nèi)部元素。而要使ReverseList采用逆序的方式遍歷其內(nèi)部元素,則只需重寫(xiě)父類(lèi)List的CreateIterator()方法,通過(guò)創(chuàng)建ReverseListIterator對(duì)象,來(lái)建立集合與具體迭代器之間的關(guān)系。

二、.Net中的Iterator模式

在.Net中,IEnumerator接口就扮演了Iterator模式中迭代器的角色。IEnumerator的定義如下:
public interface IEnumerator
{
    bool MoveNext();
    Object Current {get; }
    void Reset();
}

該接口提供了遍歷集合元素的方法,其中主要的方法是MoveNext()。它將集合中的元素下標(biāo)移到下一個(gè)元素。如果集合中沒(méi)有元素,或已經(jīng)移到了最后一個(gè),則返回false。能夠提供元素遍歷的集合對(duì)象,在.Net中都實(shí)現(xiàn)了IEnumerator接口。

我們?cè)谑褂?Net集合對(duì)象時(shí),會(huì)發(fā)現(xiàn)一個(gè)方法GetEnumerator()方法,它類(lèi)似前面提到的List對(duì)象的CreateIterator()方法。該方法返回的類(lèi)型是IEnumerator,其內(nèi)部則是創(chuàng)建并返回一個(gè)具體的迭代器對(duì)象。正是通過(guò)這個(gè)方法,建立了具體的集合對(duì)象與迭代器之間的關(guān)系。

與通常的Iterator模式實(shí)現(xiàn)不同,.Net Framework將GetEnumerator()方法單獨(dú)抽象出來(lái),定義了接口IEnumerable:
public interface IEnumerable
{
    IEnumerator GetEnumerator();
}

IEnumerable接口就像迭代功能的標(biāo)識(shí),如果集合對(duì)象需要具備迭代遍歷的功能,就必須實(shí)現(xiàn)該接口,并在具體實(shí)現(xiàn)中,創(chuàng)建與自身有關(guān)系的具體迭代器對(duì)象。而要獲得該集合對(duì)象對(duì)應(yīng)的迭代器,就可以通過(guò)該方法,如:
ArrayList al = new ArrayList();
IEnumerator iterator = al.GetEnumerator();

下面,我就以ArrayList對(duì)象為例,討論一下.Net中Iterator模式的實(shí)現(xiàn)方式。首先,我們來(lái)看看ArrayList類(lèi)的定義:
public class ArrayList : IList, ICloneable

它分別實(shí)現(xiàn)了IList和ICloneable接口。其中,ICloneable接口提供了Clone方法,與本文討論的內(nèi)容無(wú)關(guān),略過(guò)不提。IList接口則提供了和鏈表相關(guān)的操作,如Add,Remove等。這也是ArrayList和Array的不同之處。而IList接口又實(shí)現(xiàn)了ICollection接口:
public interface IList : ICollection

ICollection接口是所有集合類(lèi)型的公共接口,它提供了獲得集合長(zhǎng)度和同步處理的一些方法,不過(guò)在這里,我們需要注意的是它實(shí)現(xiàn)了IEnumerable接口:
public interface ICollection : IEnumerable

追本溯源,ArrayList類(lèi)型間接地實(shí)現(xiàn)了IEnumerable接口。在ArrayList中,IEnumerable接口的GetEnumerator()方法實(shí)現(xiàn)代碼如下:
public virtual IEnumerator GetEnumerator()
{
    return new ArrayListEnumeratorSimple(this);
}

GetEnumerator()方法是一個(gè)虛方法,這說(shuō)明,我們可以自定義一個(gè)集合類(lèi)型繼承ArrayList,重寫(xiě)這個(gè)方法,創(chuàng)建和返回不同的IEnumerator對(duì)象,從而實(shí)現(xiàn)不同的遍歷方式。

為了實(shí)現(xiàn)ArrayList的遍歷功能,采用的Iterator模式結(jié)構(gòu)如下圖所示:

iterator2.GIF

其中,類(lèi)ArrayListEnumeratorSimple的實(shí)現(xiàn)如下所示:
[Serializable]
private class ArrayListEnumeratorSimple : IEnumerator, ICloneable
{
         // Methods
         internal ArrayListEnumeratorSimple(ArrayList list)
         {
               this.list = list;
               this.index = -1;
               this.version = list._version;
               this.currentElement = list;
         }
         public object Clone(){//實(shí)現(xiàn)略}
         public virtual bool MoveNext()
         {
               if (this.version != this.list._version)
               {
                    throw new InvalidOperationException(Environment.GetResourceString(”InvalidOperation_EnumFailedVersion”));
               }
               if (this.index < (this.list.Count - 1))
               {
                      this.index++;
                      this.currentElement = this.list[this.index];
                      return true;
               }
               this.currentElement = this.list;
               this.index = this.list.Count;
               return false;
         }
         public virtual void Reset()
         {
               if (this.version != this.list._version)
               {
                      throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion"));
               }
               this.currentElement = this.list;
               this.index = -1;
         }
         // Properties
         public virtual object Current
         {
               get
               {
                      object obj1 = this.currentElement;
                      if (obj1 != this.list)
                      {
                         return obj1;
                      }
                      if (this.index == -1)
                      {
                         throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumNotStarted"));
                      }
                      throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumEnded"));
               }
         }
         // Fields
         private object currentElement;
         private int index;
         private ArrayList list;
         private int version;
}

ArrayListEnumeratorSimple實(shí)現(xiàn)了IEnumerator接口,實(shí)現(xiàn)了MoveNext()、Current、Reset()方法或?qū)傩浴T擃?lèi)是一個(gè)私有類(lèi)型,其構(gòu)造函數(shù)則被internal修飾符限制。在自定義的構(gòu)造函數(shù)中,傳入的參數(shù)類(lèi)型是ArrayList。正是通過(guò)構(gòu)造函數(shù)傳遞需要遍歷的ArrayList對(duì)象,來(lái)完成MoveNext()、Current、Reset()等操作。

下面,我們來(lái)看看如何通過(guò)IEnumerator來(lái)實(shí)現(xiàn)對(duì)ArrayList的遍歷操作。
using System;
using System.Collections;
using NUnit.Framework

[TestFixture]
public class Tester
{
 [Test]
 public void TestArrayList()
 {
            ArrayList al = new ArrayList();
           al.Add(5);
           al.Add(“Test”);
           IEnumerator e = al.GetEnumerator();
           e.MoveNext();
           Assert.AreEqual(5,e.Current);
           e.MoveNext();
           Assert.AreEqual(“Test”,e.Current);
 }
}

而要遍歷ArrayList內(nèi)部所有元素,方法也很簡(jiǎn)單:
while (e.MoveNext())
{
      Console.WriteLine(e.Current.ToString());
}

事實(shí)上,為了用戶(hù)更方便地遍歷集合對(duì)象的所有元素,在C#中提供了foreach語(yǔ)句。該語(yǔ)句的實(shí)質(zhì)正是通過(guò)IEnumerator的MoveNext()方法來(lái)完成遍歷的。下面的語(yǔ)句與剛才那段代碼是等價(jià)的:
foreach (object o in al)
{
    Console.WriteLine(o.ToString());
}

為了驗(yàn)證foreach語(yǔ)句與迭代器的關(guān)系,我們來(lái)自定義一個(gè)ReverseArrayList類(lèi)。要求遍歷這個(gè)類(lèi)的內(nèi)部元素時(shí),訪問(wèn)順序是逆序的。要定義這樣的一個(gè)類(lèi),很簡(jiǎn)單,只需要繼承ArrayList類(lèi),并重寫(xiě)GetEnumerator()方法既可。
public class ReverseArrayList:ArrayList
{
    public override IEnumerator GetEnumerator()
    {
         return new ReverseArrayListEnumerator(this);
    }
}

其中,類(lèi)ReverseArrayListEnumerator,實(shí)現(xiàn)了接口IEnumerator,它提供了逆序遍歷的迭代器:
    public class ReverseArrayListEnumerator:IEnumerator
    {
         public ReverseArrayListEnumerator(ArrayList list)
         {
             this.list = list;
             this.index = list.Count;        
             this.currentElement = list;
         }
         #region IEnumerator Members
         public virtual void Reset()
         {           
             this.currentElement = this.list;
             this.index = this.list.Count;
         }
         public virtual object Current
         {
             get
             {
                  object obj1 = this.currentElement;
                  if (obj1 != this.list)
                  {
                      return obj1;
                  }
                  if (this.index == -1)
                  {
                      throw new InvalidOperationException("Out of the Collection");
                  }
                  throw new InvalidOperationException("Out of the Collection");
             }
         }
         public virtual bool MoveNext()
         {          
             if (this.index > 0)
             {
                  this.index–;
                  this.currentElement = this.list[this.index];
                  return true;
             }
             this.currentElement = this.list;
             this.index = 0;
             return false;
         }
         #endregion

         private object currentElement;
         private int index;
         private ArrayList list;
    }

注意ReverseArrayListEnumerator類(lèi)與前面的ArrayListEnumeratorSimple類(lèi)的區(qū)別,主要在于遍歷下一個(gè)元素的順序。ReverseArrayListEnumerator中的MoveNext()方法,將下標(biāo)往前移動(dòng),以保證元素遍歷的逆序。同時(shí)在構(gòu)造函數(shù)初始化時(shí),將整個(gè)ArrayList對(duì)象的元素個(gè)數(shù)賦予下標(biāo)的初始值:
this.index = list.Count;

我們來(lái)比較一下ArrayList和ReversieArrayList類(lèi)之間,通過(guò)foreach遍歷后的結(jié)果。
         [STAThread]
         public static void Main(string[] args)
         {
             ArrayList al = new ArrayList();
             al.Add(1);
             al.Add(2);
             al.Add(3);

             ReverseArrayList ral = new ReverseArrayList();
             ral.Add(1);
             ral.Add(2);
             ral.Add(3);

             Console.WriteLine(”The Sequence ArrayList:”);
             foreach (int i in al)
             {
                  Console.Write(”{0}  “,i);
             }

             Console.WriteLine();
             Console.WriteLine(”The Reverse ArrayList:”);           
             foreach (int i in ral)
             {
                  Console.Write(”{0}  “,i);
             }
             Console.ReadLine();
         }

我們分別將數(shù)字1,2,3以同樣的順序添加到ArrayList和ReverseArrayList對(duì)象中,然后再通過(guò)foreach語(yǔ)句遍歷輸出其內(nèi)部元素。運(yùn)行后,很明顯可以看到遍歷ArrayList對(duì)象al,其順序?yàn)?,2,3;而ReverseArrayList則為3,2,1。

iterator3.GIF

由于我們應(yīng)用Iterator模式,將迭代器與集合對(duì)象完全分離,所以,即便我們完全修改了ReverseArrayList的遍歷方式,實(shí)現(xiàn)ReverseArrayList也是非常容易的,同時(shí)它并沒(méi)有影響到集合對(duì)象本身存儲(chǔ)數(shù)據(jù)對(duì)象的職能。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多