设计模式之迭代器模式2

举报
whisperrr 发表于 2021/08/19 17:00:56 2021/08/19
【摘要】  迭代器的本质:控制访问聚合对象中的元素。迭代器能实现“无须暴露聚合对象的内部实现,就能够访问到聚合对象的各个元素的功能”,做到“透明”的访问聚合对象中的元素。注意迭代器能够即“透明”访问,又可以“控制访问”聚合对象。

  执行结果

  第一个元素是:James

  最后一个元素是:Jack

  遍历元素:James

  遍历元素:Lucy

  遍历元素:Jack

  通过上面的实例演示,我们可以得到以下几点列:

  迭代器的本质:控制访问聚合对象中的元素。迭代器能实现“无须暴露聚合对象的内部实现,就能够访问到聚合对象的各个元素的功能”,做到“透明”的访问聚合对象中的元素。注意迭代器能够即“透明”访问,又可以“控制访问”聚合对象。

  迭代器的关键思想:把对聚合对象的遍历访问从聚合对象中分离出来,放入单独的迭代器中,这样聚合对象会变得简单,而且迭代器和聚合对象可以独立地变化和发展,提高系统的灵活性。

  迭代器的动机:在软件构建过程中,集合对象内部结构常常变化各异。但对于这些集合对象,我们希望在不暴露其内部结构的同时,可以让外部客户代码透明地访问其中包含的元素;同时这种“透明遍历”也为“同一种算法在多种集合对象上进行操作”提供了可能。将遍历机制抽象为“迭代器对象”为“应对变化中的集合对象”提供了一种优雅的方法

  在上面的例子中,既然聚集内部已经提供了相应的操作方法,那么我们还要使用迭代器模式呢?确实,客户端可以根据聚集提供的接口来进行遍历操作,但是,迭代器模式将迭代进行了抽象好,具有更好的扩展性,因为集合对象内部结构多变,使用迭代器模式可将客户端和聚集的责任分割开,使得两者可独立演变,迭代器模式作为中间层,可以吸收变化因素,避免客户端的修改。

  内部迭代VS外部迭代

  外部迭代器 指的是由客户端来控制迭代下一个元素的步骤,客户端会显式调用迭代器的next()等迭代方法,在遍历过程中向前进行。

  内部迭代器 指的是由迭代器自己来控制迭代下一个元素的步骤。因此,如果想要在迭代的过程中完成工作的话,客户端就需要把操作传递给迭代器,迭代器在迭代的时候会在每个元素上执行这个操作,类似于JAVA的回调机制。

  总体来说外部迭代器比内部迭代器要灵活一些,因此我们常见的实现多属于主动迭代子。

  如果一个聚集的接口没有提供修改聚集元素的方法,这样的接口就是所谓的窄接口。

  聚集对象为迭代器提供了一个宽接口,为其它对象提供窄接口来访问。即聚集对象对迭代器是适当公开的,以便迭代器对聚集对象有足够的了解,从而可以进行迭代操作。但是聚集对象应该避免向其它对象提供这些方法,其它对象应该通过迭代器完成这些操作,不能直接操作聚集对象。

  在Java中,实现这种双重限制接口的办法就是通过内部类来实现,即将迭代器对象设置为聚集类的内部类,这样迭代器对象可以对聚集类有很好的访问,同时又限制了对外的操作。 这种同时保证聚集对象的封装和迭代子功能的实现的方案叫做黑箱实现方案。 而这种形式定义的迭代器,又被称为内部迭代器。

  如下面的例子所示:

  public class NameRepository implements Container {

  public String names[] = {"Robert" , "John" ,"Julie" , "Lora"};

  @Override大连无痛人流哪家好 http://mobile.120wtrlyy.com/

  public Iterator getIterator() {

  return new NameIterator();

  }

  private class NameIterator implements Iterator {

  int index;

  @Override

  public boolean hasNext() {

  if(index < names.length){

  return true;

  }

  return false;

  }

  @Override

  public Object next() {

  if(this.hasNext()){

  return names[index++];

  }

  return null;

  }

  }

  }

  补充知识——静态迭代器和动态迭代器

  静态迭代器 静态迭代子由聚集对象创建,并持有聚集对象的一份快照(snapshot),在产生后这个快照的内容就不再变化。客户端可以继续修改原聚集的内容,但是迭代子对象不会反映出聚集的新变化。

  静态迭代子的好处是它的安全性和简易性,换言之,静态迭代子易于实现,不容易出现错误。但是由于静态迭代子将原聚集复制了一份,因此它的短处是对时间和内存资源的消耗。

  动态迭代器 动态迭代子则与静态迭代子完全相反,在迭代子被产生之后,迭代子保持着对聚集元素的引用,因此,任何对原聚集内容的修改都会在迭代子对象上反映出来。

  完整的动态迭代子不容易实现,但是简化的动态迭代子并不难实现。大多数JAVA设计师遇到的迭代子都是这种简化的动态迭代子。为了说明什么是简化的动态迭代子,首先需要介绍一个新的概念: Fail Fast。

  Fail Fast 如果一个算法开始之后,它的运算环境发生变化,使得算法无法进行必需的调整时,这个算法就应当立即发出故障信号。这就是Fail Fast的含义。

  如果聚集对象的元素在一个动态迭代子的迭代过程中发生变化时,迭代过程会受到影响而变得不能自恰。这时候,迭代子就应当立即抛出一个异常。这种迭代子就是实现了Fail Fast功能的迭代子。

  Fail Fast在JAVA聚集中的使用 JAVA语言以接口java.util.Iterator的方式支持迭代子模式,Collection接口要求提供iterator()方法,此方法在调用时返还一个Iterator类型的对象。而作为Collection接口的子类型,AbstractList类的内部成员类Itr便是实现Iterator接口的类。

  优缺点

  优点

  更好的封装性,聚集对象不需要暴露内部实现即可实现访问;

  每一个聚集对象都可以有一个或多个迭代子对象,每一个迭代子的迭代状态可以是彼此独立的。因此,一个聚集对象可以同时有几个迭代在进行之中。

  聚集内容和迭代器的分离,提高了扩展性,即可以使用不同的迭代器来遍历聚集内容。

  缺点

  迭代器种类过多,会导致类的个数增加,提高了系统的复杂性;

  在动态迭代器中易发生异常。

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。