C#设计模式之十六迭代器模式(Iterator Pattern)【行为型】

2024/3/30 1:02:45

本文主要是介绍C#设计模式之十六迭代器模式(Iterator Pattern)【行为型】,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

一、引言

   今天我们开始讲“行为型”设计模式的第三个模式,该模式是【迭代器模式】,英文名称是:Iterator Pattern。还是老套路,先从名字上来看看。“迭代器模式”我第一次看到这个名称,我的理解是,迭代是遍历的意思,迭代器可以理解为是遍历某某的工具,遍历什么呢?在软件设计中,当然遍历的是集合对象,所以说迭代器模式是遍历集合的一种通用的算法。如果集合只有一种类型,那这个模式就没用了,就是因为集合对象包含数组、列表,字典和哈希表等各种对象,如果为每一种集合对象都实现一套遍历算法,也不太实现,因此为了解决遍历集合有一个统一的接口这个事情,所以就提出了“迭代器”这个模式。

二、迭代器模式的详细介绍

2.1、动机(Motivate)

   在软件构建过程中,集合对象内部结构常常变化各异。但对于这些集合对象,我们希望在不暴露其内部结构的同时,可以让外部客户代码透明地访问其中包含的元素;同时这种“透明遍历”也为“同一种算法在多种集合对象上进行操作”提供了可能。

 使用面向对象技术将这种遍历机制抽象为“迭代器对象”为“应对变化中的集合对象”提供了一种优雅的方式。

2.2、意图(Intent)

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

2.3、结构图

      

2.4、模式的组成
    
    从迭代器模式的结构图可以看出,它涉及到四个角色,它们分别是:

    (1)、抽象迭代器(Iterator):抽象迭代器定义了访问和遍历元素的接口,一般声明如下方法:用于获取第一个元素的first(),用于访问下一个元素的next(),用于判断是否还有下一个元素的hasNext(),用于获取当前元素的currentItem(),在其子类中将实现这些方法。

    (2)、具体迭代器(ConcreteIterator):具体迭代器实现了抽象迭代器接口,完成对集合对象的遍历,同时在对聚合进行遍历时跟踪其当前位置。

    (3)、抽象聚合类(Aggregate):抽象聚合类用于存储对象,并定义创建相应迭代器对象的接口,声明一个createIterator()方法用于创建一个迭代器对象。

    (4)、具体聚合类(ConcreteAggregate):具体聚合类实现了创建相应迭代器的接口,实现了在抽象聚合类中声明的createIterator()方法,并返回一个与该具体聚合相对应的具体迭代器ConcreteIterator实例。

2.5、迭代器模式的代码实现

    迭代器模式在现实生活中也有类似的例子,比如:在部队中,我们可以让某一队伍当中的某人出列,或者让队列里面的每个人依次报名,其实这个过程就是一个遍历的过程。没什么可说的,具体实现代码如下:

  1 namespace 迭代器模式的实现
  2 {
  3     // 部队队列的抽象聚合类--该类型相当于抽象聚合类Aggregate
  4     public interface ITroopQueue
  5     {
  6         Iterator GetIterator();
  7     }
  8  
  9     // 迭代器抽象类
 10     public interface Iterator
 11     {
 12         bool MoveNext();
 13         Object GetCurrent();
 14         void Next();
 15         void Reset();
 16     }
 17  
 18     //部队队列具体聚合类--相当于具体聚合类ConcreteAggregate
 19     public sealed class ConcreteTroopQueue:ITroopQueue
 20     {
 21         private string[] collection;
 22 
 23         public ConcreteTroopQueue()
 24         {
 25             collection = new string[] { "黄飞鸿","方世玉","洪熙官","严咏春" };
 26         }
 27  
 28         public Iterator GetIterator()
 29         {
 30             return new ConcreteIterator(this);
 31         }
 32  
 33         public int Length
 34         {
 35             get { return collection.Length; }
 36         }
 37  
 38         public int GetElement(int index)
 39         {
 40             return collection[index];
 41         }
 42     }
 43  
 44     // 具体迭代器类
 45     public sealed class ConcreteIterator : Iterator
 46     {
 47         // 迭代器要集合对象进行遍历操作,自然就需要引用集合对象
 48         private ConcreteTroopQueue _list;
 49         private int _index;
 50  
 51         public ConcreteIterator(ConcreteTroopQueue list)
 52         {
 53             _list = list;
 54             _index = 0;
 55         }
 56  
 57         public bool MoveNext()
 58         {
 59             if (_index < _list.Length)
 60             {
 61                 return true;
 62             }
 63             return false;
 64         }
 65  
 66         public Object GetCurrent()
 67         {
 68             return _list.GetElement(_index);
 69         }
 70  
 71         public void Reset()
 72         {
 73             _index = 0;
 74         }
 75  
 76         public void Next()
 77         {
 78             if (_index < _list.Length)
 79             {
 80                 _index++;
 81             }
 82  
 83         }
 84     }
 85  
 86     // 客户端(Client)
 87     class Program
 88     {
 89         static void Main(string[] args)
 90         {
 91             Iterator iterator;
 92             ITroopQueue list = new ConcreteTroopQueue();
 93             iterator = list.GetIterator();
 94  
 95             while (iterator.MoveNext())
 96             {
 97                 string ren = (string)iterator.GetCurrent();
 98                 Console.WriteLine(ren);
 99                 iterator.Next();
100             }
101  
102             Console.Read();
103         }
104     }
105 }

  
三、迭代器模式的实现要点:
    
     (1)、迭代抽象:访问一个聚合对象的内容而无需暴露它的内部表示。

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

     (3)、迭代器的健壮性考虑:遍历的同时更改迭代器所在的集合结构,会导致问题。

     适用性

       (1)、访问一个聚合对象的内容而无需暴露它的内部表示。

       (2)、支持对聚合对象的多种遍历。

       (3)、为遍历不同的聚合结构提供一个统一的接口(即, 支持多态迭代)。


四、.NET 中迭代器模式的实现

     在mscorlib程序集里有这样一个命名空间,该命名空间就是:System.Collections,在该命名空间里面早已有了迭代器模式的实现。对于聚集接口和迭代器接口已经存在了,其中IEnumerator扮演的就是迭代器的角色,它的实现如下:

public interface IEnumerator
 {
      object Current
      {
           get;
      }

     bool MoveNext();

     void Reset();
 }


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

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

public interface IEnumerable
{
    IEumerator GetEnumerator();
}

    抽象聚合角色(Aggregate)和抽象迭代器角色(Iterator)分别是IEnumerable接口和IEnumerator接口,具体聚合角色(ConcreteAggregate)有Queue类型, BitArray等类型,代码如下:

  1        public sealed class BitArray : ICollection, IEnumerable, ICloneable
  2     {
  3         [Serializable]
  4         private class BitArrayEnumeratorSimple : IEnumerator, ICloneable
  5         {
  6             private BitArray bitarray;
  7 
  8             private int index;
  9 
 10             private int version;
 11 
 12             private bool currentElement;
 13 
 14             public virtual object Current
 15             {
 16                 get
 17                 {
 18                     if (this.index == -1)
 19                     {
 20                         throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumNotStarted"));
 21                     }
 22                     if (this.index >= this.bitarray.Count)
 23                     {
 24                         throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumEnded"));
 25                     }
 26                     return this.currentElement;
 27                 }
 28             }
 29 
 30             internal BitArrayEnumeratorSimple(BitArray bitarray)
 31             {
 32                 this.bitarray = bitarray;
 33                 this.index = -1;
 34                 this.version = bitarray._version;
 35             }
 36 
 37             public object Clone()
 38             {
 39                 return base.MemberwiseClone();
 40             }
 41 
 42             public virtual bool MoveNext()
 43             {
 44                 if (this.version != this.bitarray._version)
 45                 {
 46                     throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion"));
 47                 }
 48                 if (this.index < this.bitarray.Count - 1)
 49                 {
 50                     this.index++;
 51                     this.currentElement = this.bitarray.Get(this.index);
 52                     return true;
 53                 }
 54                 this.index = this.bitarray.Count;
 55                 return false;
 56             }
 57 
 58             public void Reset()
 59             {
 60                 if (this.version != this.bitarray._version)
 61                 {
 62                     throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion"));
 63                 }
 64                 this.index = -1;
 65             }
 66         }
 67 
 68         private const int BitsPerInt32 = 32;
 69 
 70         private const int BytesPerInt32 = 4;
 71 
 72         private const int BitsPerByte = 8;
 73 
 74         private int[] m_array;
 75 
 76         private int m_length;
 77 
 78         private int _version;
 79 
 80         [NonSerialized]
 81         private object _syncRoot;
 82 
 83         private const int _ShrinkThreshold = 256;
 84 
 85         [__DynamicallyInvokable]
 86         public bool this[int index]
 87         {
 88             [__DynamicallyInvokable]
 89             get
 90             {
 91                 return this.Get(index);
 92             }
 93             [__DynamicallyInvokable]
 94             set
 95             {
 96                 this.Set(index, value);
 97             }
 98         }
 99 
100         [__DynamicallyInvokable]
101         public int Length
102         {
103             [__DynamicallyInvokable]
104             get
105             {
106                 return this.m_length;
107             }
108             [__DynamicallyInvokable]
109             set
110             {
111                 if (value < 0)
112                 {
113                     throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
114                 }
115                 int arrayLength = BitArray.GetArrayLength(value, 32);
116                 if (arrayLength > this.m_array.Length || arrayLength + 256 < this.m_array.Length)
117                 {
118                     int[] array = new int[arrayLength];
119                     Array.Copy(this.m_array, array, (arrayLength > this.m_array.Length) ? this.m_array.Length : arrayLength);
120                     this.m_array = array;
121                 }
122                 if (value > this.m_length)
123                 {
124                     int num = BitArray.GetArrayLength(this.m_length, 32) - 1;
125                     int num2 = this.m_length % 32;
126                     if (num2 > 0)
127                     {
128                         this.m_array[num] &= (1 << num2) - 1;
129                     }
130                     Array.Clear(this.m_array, num + 1, arrayLength - num - 1);
131                 }
132                 this.m_length = value;
133                 this._version++;
134             }
135         }
136 
137         public int Count
138         {
139             get
140             {
141                 return this.m_length;
142             }
143         }
144 
145         public object SyncRoot
146         {
147             get
148             {
149                 if (this._syncRoot == null)
150                 {
151                     Interlocked.CompareExchange<object>(ref this._syncRoot, new object(), null);
152                 }
153                 return this._syncRoot;
154             }
155         }
156 
157         public bool IsReadOnly
158         {
159             get
160             {
161                 return false;
162             }
163         }
164 
165         public bool IsSynchronized
166         {
167             get
168             {
169                 return false;
170             }
171         }
172 
173         private BitArray()
174         {
175         }
176 
177         [__DynamicallyInvokable]
178         public BitArray(int length) : this(length, false)
179         {
180         }
181 
182         [__DynamicallyInvokable]
183         public BitArray(int length, bool defaultValue)
184         {
185             if (length < 0)
186             {
187                 throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
188             }
189             this.m_array = new int[BitArray.GetArrayLength(length, 32)];
190             this.m_length = length;
191             int num = defaultValue ? -1 : 0;
192             for (int i = 0; i < this.m_array.Length; i++)
193             {
194                 this.m_array[i] = num;
195             }
196             this._version = 0;
197         }
198 
199         [__DynamicallyInvokable]
200         public BitArray(byte[] bytes)
201         {
202             if (bytes == null)
203             {
204                 throw new ArgumentNullException("bytes");
205             }
206             if (bytes.Length > 268435455)
207             {
208                 throw new ArgumentException(Environment.GetResourceString("Argument_ArrayTooLarge", new object[]
209                 {
210                     8
211                 }), "bytes");
212             }
213             this.m_array = new int[BitArray.GetArrayLength(bytes.Length, 4)];
214             this.m_length = bytes.Length * 8;
215             int num = 0;
216             int num2 = 0;
217             while (bytes.Length - num2 >= 4)
218             {
219                 this.m_array[num++] = ((int)(bytes[num2] & 255) | (int)(bytes[num2 + 1] & 255) << 8 | (int)(bytes[num2 + 2] & 255) << 16 | (int)(bytes[num2 + 3] & 255) << 24);
220                 num2 += 4;
221             }
222             switch (bytes.Length - num2)
223             {
224             case 1:
225                 goto IL_103;
226             case 2:
227                 break;
228             case 3:
229                 this.m_array[num] = (int)(bytes[num2 + 2] & 255) << 16;
230                 break;
231             default:
232                 goto IL_11C;
233             }
234             this.m_array[num] |= (int)(bytes[num2 + 1] & 255) << 8;
235             IL_103:
236             this.m_array[num] |= (int)(bytes[num2] & 255);
237             IL_11C:
238             this._version = 0;
239         }
240 
241         [__DynamicallyInvokable]
242         public BitArray(bool[] values)
243         {
244             if (values == null)
245             {
246                 throw new ArgumentNullException("values");
247             }
248             this.m_array = new int[BitArray.GetArrayLength(values.Length, 32)];
249             this.m_length = values.Length;
250             for (int i = 0; i < values.Length; i++)
251             {
252                 if (values[i])
253                 {
254                     this.m_array[i / 32] |= 1 << i % 32;
255                 }
256             }
257             this._version = 0;
258         }
259 
260         [__DynamicallyInvokable]
261         public BitArray(int[] values)
262         {
263             if (values == null)
264             {
265                 throw new ArgumentNullException("values");
266             }
267             if (values.Length > 67108863)
268             {
269                 throw new ArgumentException(Environment.GetResourceString("Argument_ArrayTooLarge", new object[]
270                 {
271                     32
272                 }), "values");
273             }
274             this.m_array = new int[values.Length];
275             this.m_length = values.Length * 32;
276             Array.Copy(values, this.m_array, values.Length);
277             this._version = 0;
278         }
279 
280         [__DynamicallyInvokable]
281         public BitArray(BitArray bits)
282         {
283             if (bits == null)
284             {
285                 throw new ArgumentNullException("bits");
286             }
287             int arrayLength = BitArray.GetArrayLength(bits.m_length, 32);
288             this.m_array = new int[arrayLength];
289             this.m_length = bits.m_length;
290             Array.Copy(bits.m_array, this.m_array, arrayLength);
291             this._version = bits._version;
292         }
293 
294         [__DynamicallyInvokable]
295         public bool Get(int index)
296         {
297             if (index < 0 || index >= this.Length)
298             {
299                 throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_Index"));
300             }
301             return (this.m_array[index / 32] & 1 << index % 32) != 0;
302         }
303 
304         [__DynamicallyInvokable]
305         public void Set(int index, bool value)
306         {
307             if (index < 0 || index >= this.Length)
308             {
309                 throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_Index"));
310             }
311             if (value)
312             {
313                 this.m_array[index / 32] |= 1 << index % 32;
314             }
315             else
316             {
317                 this.m_array[index / 32] &= ~(1 << index % 32);
318             }
319             this._version++;
320         }
321 
322         [__DynamicallyInvokable]
323         public void SetAll(bool value)
324         {
325             int num = value ? -1 : 0;
326             int arrayLength = BitArray.GetArrayLength(this.m_length, 32);
327             for (int i = 0; i < arrayLength; i++)
328             {
329                 this.m_array[i] = num;
330             }
331             this._version++;
332         }
333 
334         [__DynamicallyInvokable]
335         public BitArray And(BitArray value)
336         {
337             if (value == null)
338             {
339                 throw new ArgumentNullException("value");
340             }
341             if (this.Length != value.Length)
342             {
343                 throw new ArgumentException(Environment.GetResourceString("Arg_ArrayLengthsDiffer"));
344             }
345             int arrayLength = BitArray.GetArrayLength(this.m_length, 32);
346             for (int i = 0; i < arrayLength; i++)
347             {
348                 this.m_array[i] &= value.m_array[i];
349             }
350             this._version++;
351             return this;
352         }
353 
354         [__DynamicallyInvokable]
355         public BitArray Or(BitArray value)
356         {
357             if (value == null)
358             {
359                 throw new ArgumentNullException("value");
360             }
361             if (this.Length != value.Length)
362             {
363                 throw new ArgumentException(Environment.GetResourceString("Arg_ArrayLengthsDiffer"));
364             }
365             int arrayLength = BitArray.GetArrayLength(this.m_length, 32);
366             for (int i = 0; i < arrayLength; i++)
367             {
368                 this.m_array[i] |= value.m_array[i];
369             }
370             this._version++;
371             return this;
372         }
373 
374         [__DynamicallyInvokable]
375         public BitArray Xor(BitArray value)
376         {
377             if (value == null)
378             {
379                 throw new ArgumentNullException("value");
380             }
381             if (this.Length != value.Length)
382             {
383                 throw new ArgumentException(Environment.GetResourceString("Arg_ArrayLengthsDiffer"));
384             }
385             int arrayLength = BitArray.GetArrayLength(this.m_length, 32);
386             for (int i = 0; i < arrayLength; i++)
387             {
388                 this.m_array[i] ^= value.m_array[i];
389             }
390             this._version++;
391             return this;
392         }
393 
394         [__DynamicallyInvokable]
395         public BitArray Not()
396         {
397             int arrayLength = BitArray.GetArrayLength(this.m_length, 32);
398             for (int i = 0; i < arrayLength; i++)
399             {
400                 this.m_array[i] = ~this.m_array[i];
401             }
402             this._version++;
403             return this;
404         }
405 
406         public void CopyTo(Array array, int index)
407         {
408             if (array == null)
409             {
410                 throw new ArgumentNullException("array");
411             }
412             if (index < 0)
413             {
414                 throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
415             }
416             if (array.Rank != 1)
417             {
418                 throw new ArgumentException(Environment.GetResourceString("Arg_RankMultiDimNotSupported"));
419             }
420             if (array is int[])
421             {
422                 Array.Copy(this.m_array, 0, array, index, BitArray.GetArrayLength(this.m_length, 32));
423                 return;
424             }
425             if (array is byte[])
426             {
427                 int arrayLength = BitArray.GetArrayLength(this.m_length, 8);
428                 if (array.Length - index < arrayLength)
429                 {
430                     throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
431                 }
432                 byte[] array2 = (byte[])array;
433                 for (int i = 0; i < arrayLength; i++)
434                 {
435                     array2[index + i] = (byte)(this.m_array[i / 4] >> i % 4 * 8 & 255);
436                 }
437                 return;
438             }
439             else
440             {
441                 if (!(array is bool[]))
442                 {
443                     throw new ArgumentException(Environment.GetResourceString("Arg_BitArrayTypeUnsupported"));
444                 }
445                 if (array.Length - index < this.m_length)
446                 {
447                     throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
448                 }
449                 bool[] array3 = (bool[])array;
450                 for (int j = 0; j < this.m_length; j++)
451                 {
452                     array3[index + j] = ((this.m_array[j / 32] >> j % 32 & 1) != 0);
453                 }
454                 return;
455             }
456         }
457 
458         public object Clone()
459         {
460             return new BitArray(this.m_array)
461             {
462                 _version = this._version,
463                 m_length = this.m_length
464             };
465         }
466 
467         [__DynamicallyInvokable]
468         public IEnumerator GetEnumerator()
469         {
470             return new BitArray.BitArrayEnumeratorSimple(this);
471         }
472 
473         private static int GetArrayLength(int n, int div)
474         {
475             if (n <= 0)
476             {
477                 return 0;
478             }
479             return (n - 1) / div + 1;
480         }
481     }

   还有很多类型,就不一一列举了,大家可以查看源代码,每个元素都可以在迭代器模式的构造图上找到对应的元素。

   具体的类型和代码截图如下:

     
  
五、总结

    今天到此就把迭代器模式写完了,该模式不是很难,结构也不是很复杂,Net框架里面也有现成的实现。并且在 Net 2.0里面还有升级的实现,要想学习该模式,可以好好看看该模式在Net 框架中的实现,受益匪浅。



这篇关于C#设计模式之十六迭代器模式(Iterator Pattern)【行为型】的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程