設計模式之迭代器模式
迭代器模式 Iterator
Intro
迭代器模式,提供一種方法順序訪問一個聚合對象中的各個元素,而又不暴露該對象的內部表示。
迭代器模式是分離了集合對象的遍歷行為,抽象出一個迭代器類來負責,這樣既可以做到不暴露集合的內部結構,又可以讓外部代碼透明地訪問集合內部的數據。
使用場景
當你需要訪問一個聚集對象,而且不管這些對象是什麼都需要遍歷的時候,你就應該考慮用迭代器模式。
當你需要對聚集有多種方式遍歷時,可以考慮用迭代器模式。
實現方式
如果要自己實現需要有下面幾個類:
一個迭代器抽象類(或接口)
一個聚集抽象類(或接口)
具體實現的迭代器類
具體實現的聚集類
Sample
public abstract class Iterator
{
public abstract object First();
public abstract object Next();
public abstract bool IsDone();
public abstract object CurrentItem();
}
public class ConcreteIterator : Iterator
{
private readonly ConcreteAggregate _aggregate;
private int _current = 0;
public ConcreteIterator(ConcreteAggregate aggregate) => _aggregate = aggregate;
public override object First()
{
return _aggregate[0];
}
public override object Next()
{
_current++;
return _current >= _aggregate.TotalCount ? null : _aggregate[_current];
}
public override bool IsDone() => _current >= _aggregate.TotalCount;
public override object CurrentItem() => _aggregate[_current];
}
public abstract class Aggregate
{
/// <summary>
/// 創建迭代器
/// </summary>
/// <returns></returns>
public abstract Iterator CreateIterator();
}
public class ConcreteAggregate : Aggregate
{
private readonly IList<object> _items = new List<object>();
public override Iterator CreateIterator()
{
return new ConcreteIterator(this);
}
public int TotalCount => _items.Count;
public object this[int index]
{
get => _items[index];
set => _items.Insert(index, value);
}
}
var aggregate = new ConcreteAggregate
{
[0] = "大鳥",
[1] = "小菜",
[2] = "行李",
[3] = "老外",
[4] = "公交員工",
[5] = "小偷"
};
Iterator iterator = new ConcreteIterator(aggregate);
do
{
Console.WriteLine($"{iterator.CurrentItem()} 請買車票");
iterator.Next();
} while (!iterator.IsDone());
More
需要注意的是,使用迭代器模式遍歷集合時,不要對集合進行增加元素或者刪除元素操作
在 C# 中實現 IEnumerable
接口就可以比較方便的實現一個迭代器,foreach
就是迭代器的一個語法糖
來看一下 IEnumerabe
的定義:
// 聚集抽象
public interface IEnumerable
{
/// <summary>Returns an enumerator that iterates through a collection.</summary>
/// <returns>An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.</returns>
IEnumerator GetEnumerator();
}
// 迭代器抽象
public interface IEnumerator
{
/// <summary>Advances the enumerator to the next element of the collection.</summary>
/// <returns>
/// <see langword="true" /> if the enumerator was successfully advanced to the next element; <see langword="false" /> if the enumerator has passed the end of the collection.</returns>
/// <exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created.</exception>
bool MoveNext();
/// <summary>Gets the element in the collection at the current position of the enumerator.</summary>
/// <returns>The element in the collection at the current position of the enumerator.</returns>
object Current { get; }
/// <summary>Sets the enumerator to its initial position, which is before the first element in the collection.</summary>
/// <exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created.</exception>
void Reset();
}
最後留個思考題給你,List 在 foreach
的時候如果刪除一個元素會發生什麼?內部是怎麼樣實現的呢? 可以自己實踐一下