迭代器模式是一种行为型设计模式,它提供了一种统一的方式来访问集合对象中的元素,而不是暴露集合内部的表示方式。简单地说,就是将遍历集合的责任封装到一个单独的对象中,我们可以按照特定的方式访问集合中的元素。
抽象迭代器(Iterator):定义了遍历聚合对象所需的方法,包括hashNext()和next()方法等,用于遍历聚合对象中的元素。
具体迭代器(Concrete Iterator):它是实现迭代器接口的具体实现类,负责具体的遍历逻辑。它保存了当前遍历的位置信息,并可以根据需要向前或向后遍历集合元素。
抽象聚合器(Aggregate): 一般是一个接口,提供一个iterator()方法,例如java中的Collection接口,List接口,Set接口等。
具体聚合器(ConcreteAggregate):就是抽象容器的具体实现类,比如List接口的有序列表实现ArrayList,List接口的链表实现LinkList,Set接口的哈希列表的实现HashSet等。
简单来说就是容器的种类我们不需要知道是什么(List,HasSet等)我们只要获取到迭代器就可以进行遍历。
下面使用两个例子来说明
抽象聚合器
abstract class Aggregate
{
public abstract Iterator CreateIterator();
}
具体聚合器
class ConcreteAggregate : Aggregate
{
private ArrayList _items = new ArrayList();
public override Iterator CreateIterator()
{
return new ConcreteIterator(this);
}
// Gets item count
public int Count
{
get { return _items.Count; }
}
// Indexer
public object this[int index]
{
get { return _items[index]; }
set { _items.Insert(index, value); }
}
}
抽象迭代器
abstract class Iterator
{
public abstract object First();
public abstract object Next();
public abstract bool IsDone();
public abstract object CurrentItem();
}
具体迭代器
class ConcreteIterator : Iterator
{
private ConcreteAggregate _aggregate;
private int _current = 0;
// Constructor
public ConcreteIterator(ConcreteAggregate aggregate)
{
this._aggregate = aggregate;
}
// Gets first iteration item
public override object First()
{
return _aggregate[0];
}
// Gets next iteration item
public override object Next()
{
object ret = null;
if (_current < _aggregate.Count - 1)
{
ret = _aggregate[++_current];
}
return ret;
}
// Gets current iteration item
public override object CurrentItem()
{
return _aggregate[_current];
}
// Gets whether iterations are complete
public override bool IsDone()
{
return _current >= _aggregate.Count;
}
}
public class IteratorStructure : MonoBehaviour
{
void Start ( )
{
ConcreteAggregate a = new ConcreteAggregate();
a[0] = "Item A";
a[1] = "Item B";
a[2] = "Item C";
a[3] = "Item D";
// Create Iterator and provide aggregate
Iterator i = a.CreateIterator();
Debug.Log("Iterating over collection:");
object item = i.First();
while (item != null)
{
Debug.Log(item);
item = i.Next();
}
}
}
这里使用一个不同年代的歌曲集来进行演示
歌曲信息
public class SongInfo
{
public string songName { get; protected set; }
public string bandName { get; protected set; }
public int yearReleased { get; protected set; }
public SongInfo(string songName, string bandName, int yearReleased)
{
this.songName = songName;
this.bandName = bandName;
this.yearReleased = yearReleased;
}
public string ToStringEx()
{
return this.songName + " - " + this.bandName + " : " + this.yearReleased.ToString();
}
}
抽象迭代器
public interface SongIterator
{
IEnumerator GetIterator();
}
70年代歌曲,既是迭代器又是聚合器
public class SongsOfThe70s : SongIterator
{
// here it is a list
protected List<SongInfo> bestSongs;
public SongsOfThe70s()
{
bestSongs = new List<SongInfo>();
}
public void AddSong(string name, string artist, int year)
{
SongInfo song = new SongInfo(name, artist, year);
bestSongs.Add(song);
}
//about yeild return :http://www.jb51.net/article/54810.htm
// heart
public IEnumerator GetIterator()
{
foreach (SongInfo song in bestSongs)
yield return song;
yield break;
}
}
80年代歌曲,既是迭代器又是聚合器
public class SongsOfThe80s : SongIterator
{
// here we have an array
protected SongInfo[] bestSongs;
public SongsOfThe80s()
{
bestSongs = new SongInfo[0];
}
public void AddSong(string name, string artist, int year)
{
SongInfo song = new SongInfo(name, artist, year);
// just for the sake of easyness of appending something we will convert the array to a list
List<SongInfo> newSongs = new List<SongInfo>(bestSongs);
// add a new element
newSongs.Add(song);
// and convert it back to an array
bestSongs = newSongs.ToArray();
}
// heart
public IEnumerator GetIterator()
{
foreach (SongInfo song in bestSongs)
yield return song;
yield break;
}
}
void Start()
{
// creating the collections and adding some songs:
SongsOfThe70s song70s = new SongsOfThe70s();
song70s.AddSong("song title", "song artist", 1974);
song70s.AddSong("song title2", "song artist2", 1978);
SongsOfThe80s song80s = new SongsOfThe80s();
song80s.AddSong("song title 80s", "song artist 80s", 1985);
song80s.AddSong("song title2 80s", "song artist2 80s", 1989);
// because of the iterator pattern we can loop through both types
// of collections the same simple way and don't have to bother
// with what type of collection the object stores:
IEnumerator songsOfThe70sIterator = song70s.GetIterator();
while (songsOfThe70sIterator.MoveNext())
{
SongInfo info = (SongInfo)songsOfThe70sIterator.Current;
Debug.Log("Song 70s: " + info.ToStringEx());
}
IEnumerator songsOfThe80sIterator = song80s.GetIterator();
while (songsOfThe80sIterator.MoveNext())
{
SongInfo info = (SongInfo)songsOfThe80sIterator.Current;
Debug.Log("Song 80s: " + info.ToStringEx());
}
}