迭代器模式-提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的结构
每一种数据结构(包括自定义)遍历自身内部的数据方式都是不同的。
但是我们又希望和常规的遍历方式一样调用,就如for和foreach一样遍历。
想要以相同的方式遍历不同类型的聚合对象,首先就要有一个相同的接口方法来统一获取,我们可以自定义,也可以使用C#自带的IEnumerable。注意:只有继承于IEnumerable的接口才能使用foreach。否则只能使用for或者while来遍历。
能够遍历一个聚合对象的数据主要看2点,是否存在值,以及取出该值。那么由此,就可以再次定义一个接口实现上述的2点。我们仍然可以自定义或者采用C#自带的IEnumerator
定义一个聚合类继承于IEnumerable,实现GetEnumerator()方法。定义一个迭代器类继承于IEnumerator,在这个迭代器中实现真正迭代的逻辑。在GetEnumerator中返回这个迭代器。最后使用foreach去直接遍历这个聚合类或者使用for或者while去处理IEnumerator。
下面用代码来说明:
先采用自定义的方式
1.根据上述说明,我们需要在聚合类中统一接口来获取一个统一的迭代器
定义迭代器接口
public interface IAnimalIterator
{
//是否存在下一项的值
bool HasNext();
//下一项的值
object Next();
}
定义获取方法接口
public interface IAnimal
{
IAnimalIterator GetAnimals();
}
2.定义聚合类,并继承于IAnimal
public class Duck:IAnimal
{
private static int MAX = 7;
//可以采用其他实体类型
private string[] Names = new string[MAX];
public Duck()
{
Names[0] = "第零只鸭子";
Names[1] = "第一只鸭子";
Names[2] = "第二只鸭子";
Names[3] = "第三只鸭子";
Names[4] = "第四只鸭子";
Names[5] = "第五只鸭子";
Names[6] = "第六只鸭子";
}
//实现接口
public IAnimalIterator GetAnimals()
{
return new DuckIterator(Names);
}
}
3.定义迭代器类,继承迭代器接口
public class DuckIterator:IAnimalIterator
{
private readonly string[] _name;
int _position = 0;
public DuckIterator(string[] name)
{
_name = name;
}
public bool HasNext()
{
if (_position >= _name.Length || _name[_position] == null)
return false;
return true;
}
public object Next()
{
string name = _name[_position];
_position++;
return name;
}
}
4.调用,遍历Duck中的Name
Duck duck = new Duck();
var iterator = duck.GetAnimals();
while (iterator.HasNext())
{
Console.WriteLine((string)iterator.Next());
}
5.新建一个聚合类
public class Duck:IAnimal
{
private static int MAX = 7;
private string[] Names = new string[MAX];
public Duck()
{
Names[0] = "第零只鸭子";
Names[1] = "第一只鸭子";
Names[2] = "第二只鸭子";
Names[3] = "第三只鸭子";
Names[4] = "第四只鸭子";
Names[5] = "第五只鸭子";
Names[6] = "第六只鸭子";
}
public IAnimalIterator GetAnimals()
{
return new DuckIterator(Names);
}
}
6.为新建的Chicken类添加一个迭代器
public class ChickenIterator:IAnimalIterator
{
private readonly List<string> _name;
private int _position = 0;
public ChickenIterator(List<string> name)
{
_name = name;
}
public bool HasNext()
{
//和duck几乎一样,只是count和length的区别
if (_position >= _name.Count || _name[_position] == null)
return false;
return true;
}
public object Next()
{
string name = _name[_position];
_position++;
return name;
}
}
7.调用
Chicken chicken = new Chicken();
var chickenIterator = chicken.GetAnimals();
while (chickenIterator.HasNext())
{
Console.WriteLine((string)chickenIterator.Next());
}
和Duck的调用也几乎一样,可封装一下方法
8.
static void Main(string[] args)
{
Duck duck = new Duck();
var duckIterator = duck.GetAnimals();
Get(duckIterator);
Chicken chicken = new Chicken();
var chickenIterator = chicken.GetAnimals();
Get(chickenIterator);
Console.ReadLine();
}
static void Get(IAnimalIterator iterator)
{
while (iterator.HasNext())
{
Console.WriteLine((string)iterator.Next());
}
}
上面讲了自定义迭代器,实际上C#已经实现了迭代器,就是IEnumerable和IEnumerator
下面将自定义的迭代器换成C#
1.聚合类
Duck
public class Duck:IEnumerable
{
private static int MAX = 7;
private string[] Names = new string[MAX];
public Duck()
{
Names[0] = "第零只鸭子";
Names[1] = "第一只鸭子";
Names[2] = "第二只鸭子";
Names[3] = "第三只鸭子";
Names[4] = "第四只鸭子";
Names[5] = "第五只鸭子";
Names[6] = "第六只鸭子";
}
// public IAnimalIterator GetAnimals()
// {
// return new DuckIterator(Names);
// }
public IEnumerator GetEnumerator()
{
return new DuckIterator(Names);
}
}
Chicken
public class Chicken:IEnumerable
{
private List<string> Names;
public Chicken()
{
Names = new List<string>();
Names.Add("第0只鸡");
Names.Add("第1只鸡");
Names.Add("第2只鸡");
Names.Add("第3只鸡");
Names.Add("第4只鸡");
}
// public IAnimalIterator GetAnimals()
// {
// return new ChickenIterator(Names);
// }
public IEnumerator GetEnumerator()
{
return new ChickenIterator(Names);
}
}
2.迭代器类
DuckIterator
public class DuckIterator:IEnumerator
{
private readonly string[] _name;
int _position = 0;
public DuckIterator(string[] name)
{
_name = name;
}
// public bool HasNext()
// {
// if (_position >= _name.Length || _name[_position] == null)
// return false;
// return true;
// }
//
// public object Next()
// {
// string name = _name[_position];
// _position++;
// return name;
// }
public bool MoveNext()
{
if (_position >= _name.Length || _name[_position] == null)
return false;
return true;
}
public void Reset()
{
_position = 0;
}
public object Current
{
get
{
string name = _name[_position];
_position++;
return name;
}
}
}
ChickenIterator
public class ChickenIterator:IEnumerator
{
private readonly List<string> _name;
private int _position = 0;
public ChickenIterator(List<string> name)
{
_name = name;
}
// public bool HasNext()
// {
// if (_position >= _name.Count || _name[_position] == null)
// return false;
// return true;
// }
//
// public object Next()
// {
// string name = _name[_position];
// _position++;
// return name;
// }
public bool MoveNext()
{
if (_position >= _name.Count || _name[_position] == null)
return false;
return true;
}
public void Reset()
{
_position = 0;
}
public object Current
{
get
{
string name = _name[_position];
_position++;
return name;
}
}
}
调用
class Program
{
static void Main(string[] args)
{
Duck duck = new Duck();
var duckIterator = duck.GetEnumerator();
Get(duckIterator);
Chicken chicken = new Chicken();
var chickenIterator = chicken.GetEnumerator();
Get(chickenIterator);
Console.ReadLine();
}
static void Get(IEnumerator iterator)
{
while (iterator.MoveNext())
{
Console.WriteLine((string)iterator.Current);
}
}
}
当然,如果需要迭代的类型已经是迭代类型,我们直接返回这个这个类型的迭代器就可以了,不需要自己去实现一个迭代器
public IEnumerator GetEnumerator()
{
//return new ChickenIterator(Names);
//不需要去自定义一个迭代器了,因为List本来就继承于迭代器
return Names.GetEnumerator();
}