迭代器模式
迭代器模式的定义:提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。
我们还是照旧,先来看看迭代器模式的结构图:
为了帮助理解,有必要贴一下聚合对象的createIterator()方法的代码:
public Iterator createIterator() { //此处可用工厂方法来选择一个迭代器的对象,将自身实例传给迭代器对象 return new ConcreteIterator(this); }
其实迭代器的关键思想是把对聚合对象的遍历和访问从聚合对象中分离出来,放入单独的迭代器中。其实又是一个分层的思想,通过Iterator(迭代器)来操作Aggregate(聚合对象)。如果把遍历和访问逻辑全写在聚合对象里的话,会严重影响到聚合对象的可扩展性和可维护性。这样迭代器和聚合对象可以各自独立的变化和发展,会大大加强系统的灵活性。所以在迭代器模式的定义里说了“不暴露该对象的内部表示”。
而.Net中也有对迭代器模式的简单实现,我们来用结构图对应一下:
.Net中,聚合接口是IEnumerable,迭代器接口是IEnumerator,而像List、数组等聚合对象都实现了IEnumerable,所以它们都能通过聚合对象.GetEnumerator()把自己传给一个迭代器,然后由这个迭代器来遍历自己。
而我们经常写的代码
List<string> a=new List<string>(); foreach(string item in a) { } string[] b=new string[]{} ; foreach(string item in b) { }
其实编译器会帮我们生成使用迭代器的代码
List<string> a=new List<string>(); IEnumerator<string> e=a.GetEnumerator(); while(e.MoveNext) { } string[] b=new string[]{}; IEnumerator<string> e=b.GetEnumerator(); while(e.MoveNext) { }
所以迭代器模式还有一个好处就是,即使不同的聚合对象,如此处是List和string[],也可以通过相同迭代器来操作它们,所以在客户端,看起来就像操作相同的聚合对象一样。 既然可以通过相同的迭代器来访问不同的聚合对象,自然可以用不同的迭代器来访问相同的聚合对象,这样同一个聚合对象,就会有多种不同的遍历方法。就像上边的例子一样,
public Iterator createIterator() { //此处可用工厂方法来选择一个迭代器的对象,将自身实例传给迭代器对象 return new ConcreteIterator(this); } 可以在此方法里面选择不同的迭代器,由于每个迭代器的遍历逻辑都不一样,所以可以实现很多不同的功能。这些得益于聚合对象将遍历逻辑放到迭代器里实现的好处。
.Net中只是对迭代器模式的简单实现,在很多现实项目中,可能有很多复杂的个性化的运用:
比如对一个聚合对象的遍历,我们也许会考虑到各部门权限的不同,可能各个部门都有些聚合对象里的元素不能访问等等。我们就可以通过在迭代器的遍历逻辑里加入权限的判断,来过滤聚合对象里的元素。还可以定义多个迭代器,比如财务部门迭代器、开发部门迭代器等,然后在createIterator()或GetEnumerator()通过权限判断运用工厂模式实例化不同的迭代器来实现。
再比如,有可能有双向迭代的需求,就是要求对一个聚合对象里的元素,不仅仅可以访问下一个元素,还可以访问上一个元素,这些遍历逻辑都可以通过写在迭代器里来实现。
所以迭代器模式的本质:控制访问聚合对象中的元素。 通过在迭代器中写各种遍历逻辑来控制访问聚合对象中的元素。