设计模式之迭代器模式
迭代器模式
概念
Iterator is a behavioral design pattern that lets you traverse elements of a collection without exposing its underlying representation (list, stack, tree, etc.).
迭代器模式是一种行为设计模式, 让你能在不暴露集合底层表现形式 (列表、 栈和树等) 的情况下遍历集合中所有的元素。
场景
当一个类内部有复杂的数据结构,有可能是链表、树、图等,使用者需要遍历这个类所有的成员的时候,可能会自己编写编写算法。
迭代器模式就是抽取接口,对外隐藏复杂的数据结构,仅仅提供一个简单的遍历接口的模式。
这种模式的好处是,遍历算法可能是复杂的,多样的。例如同样是树结构,也可以写出深度遍历和层次遍历两种不同的遍历算法。
迭代器模式就是封装多种不同类型的遍历算法,提供统一的接口,通常情况下,使用者可以获取当前元素,下一个元素,剩余的元素这些方法。
案例
先看一个简单的例子,这个类内部的数据结构是线性表,比较好遍历
首先有这样一个集合,可以添加元素,提取元素等,集合本身不是先迭代的方法,内部会使用一个迭代器来迭代所有元素
为了满足这个要求,抽一个接口
abstract class IteratorAggregate : IEnumerable { public abstract IEnumerator GetEnumerator(); }
集合实现接口,并另外封装迭代器
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); } }
现在开始实现迭代器
先定好接口
abstract class Iterator : IEnumerator { object IEnumerator.Current => Current(); public abstract int Key(); public abstract object Current(); public abstract bool MoveNext(); public abstract void Reset(); }
然后让迭代器实现接口,由于是线性表,接口实现起来很容易。
只需要记录一个指针,指向当前元素。如果需要下一个元素,就把指针往后头移动。如果反向便利,就把指针往前头移动。
class AlphabeticalOrderIterator : Iterator { private WordsCollection _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; } }
现在可以遍历集合了,注意c#语言实现IEnumerable接口的都可以写foreach
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); }