旧游无处不堪寻
无寻处,惟有少年心
设计模式-迭代器

迭代器模式(Iterator Pattern)是一种行为型设计模式,让你能在不暴露集合底层表现形式(列表、栈和树等)的情况下遍历集合中所有的元素。

解释


集合是编程中最常使用的数据类型之一。无论集合的构成方式如何,它都必须提供某种访问元素的方式,便于其他代码使用其中的元素。集合应提供一种能够遍历元素的方式,且保证它不会周而复始地访问同一个元素。

迭代器模式的主要思想是将集合的遍历行为抽取为单独的迭代器对象

除实现自身算法外,迭代器还封装了遍历操作的所有细节,多个迭代器可以在相互独立的情况下同时访问集合。
迭代器通常会提供一个获取集合元素的基本方法。客户端可不断调用该方法直至它不返回任何内容,这意味着迭代器已经遍历了所有元素。

所有迭代器必须实现相同的接口。这样一来,只要有合适的迭代器,客户端代码就能兼容任何类型的集合或遍历算法。如果你需要采用特殊方式来遍历集合,只需创建一个新的迭代器类即可,无需对集合或客户端进行修改。

迭代器模式 UML


适用场景


  1. 当集合背后为复杂的数据结构,且你希望对客户端隐藏其复杂性时,可以使用迭代器模式
  2. 使用该模式可以减少程序中重复的遍历代码
  3. 如果你希望代码能够遍历不同的甚至是无法预知的数据结构,可以使用迭代器模式

代码示例


using System;
namespace IteratorPatternDemo
{
abstract class Iterator : IEnumerator
{
object IEnumerator.Current => Current();

// Returns the key of the current element
public abstract int Key();

// Returns the current element
public abstract object Current();

// Move forward to next element
public abstract bool MoveNext();

// Rewinds the Iterator to the first element
public abstract void Reset();
}

abstract class IteratorAggregate : IEnumerable
{
// Returns an Iterator or another IteratorAggregate for the implementing
// object.
public abstract IEnumerator GetEnumerator();
}

// Concrete Iterators implement various traversal algorithms. These classes
// store the current traversal position at all times.
class AlphabeticalOrderIterator : Iterator
{
private WordsCollection _collection;

// Stores the current traversal position. An iterator may have a lot of
// other fields for storing iteration state, especially when it is
// supposed to work with a particular kind of collection.
private int _position = -1;

private bool _reverse = false;

public AlphabeticalOrderIterator(WordsCollection collection, bool reverse = false)
{
this._collection = collection;
this._reverse = reverse;

if (reverse)
{
this._position = collection.getItems().Count;
}
}

public override object Current()
{
return this._collection.getItems()[_position];
}

public override int Key()
{
return this._position;
}

public override bool MoveNext()
{
int updatedPosition = this._position + (this._reverse ? -1 : 1);

if (updatedPosition >= 0 && updatedPosition < this._collection.getItems().Count)
{
this._position = updatedPosition;
return true;
}
else
{
return false;
}
}

public override void Reset()
{
this._position = this._reverse ? this._collection.getItems().Count - 1 : 0;
}
}

// Concrete Collections provide one or several methods for retrieving fresh
// iterator instances, compatible with the collection class.
class WordsCollection : IteratorAggregate
{
List<string> _collection = new List<string>();

bool _direction = false;

public void ReverseDirection()
{
_direction = !_direction;
}

public List<string> getItems()
{
return _collection;
}

public void AddItem(string item)
{
this._collection.Add(item);
}

public override IEnumerator GetEnumerator()
{
return new AlphabeticalOrderIterator(this, _direction);
}
}

class Program
{
static void Main(string[] args)
{
// The client code may or may not know about the Concrete Iterator
// or Collection classes, depending on the level of indirection you
// want to keep in your program.
var collection = new WordsCollection();
collection.AddItem("First");
collection.AddItem("Second");
collection.AddItem("Third");

Console.WriteLine("Straight traversal:");

foreach (var element in collection)
{
Console.WriteLine(element);
}

Console.WriteLine("\nReverse traversal:");

collection.ReverseDirection();

foreach (var element in collection)
{
Console.WriteLine(element);
}
// output

// Straight traversal:
// First
// Second
// Third

// Reverse traversal:
// Third
// Second
// First
}
}
}