前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >迭代器模式浅析

迭代器模式浅析

作者头像
孟君
发布2020-04-24 16:06:57
4930
发布2020-04-24 16:06:57
举报
文章被收录于专栏:孟君的编程札记

在平时我们会遇到需要顺序访问一个对象集的元素的场景,比如:老师按照名单进行点名;去图书馆,在某一栏书架上从左到右或者从右到左查找想要借的书;又如开车的时候,想听音乐或者收音机电台,一个个地查找等等。

这种一个一个遍历的场景就是今天我们要讲的迭代器模式。在Java语言的聚集(Collection)框架中,广泛使用了迭代器来遍历聚集的元素。

一. 迭代器模式的基本介绍

意图

提供一种方法顺序访问一个聚合对象中各个元素,而不是暴露该对象的内部表示。

结构

迭代器模式的基本结构如下:

这里涉及到的参与者有如下几种:

  • Iterator(迭代器)
    • 迭代器定义访问和遍历元素的接口
  • ConcreteIterator(具体迭代器)
    • 具体迭代器实现迭代器接口
    • 对该聚合遍历时跟踪当前位置
  • Aggregate(聚合)
    • 聚合定义创建相应迭代器对象接口
  • ConcreteAggregate(具体聚合)
    • 具体聚合实现创建相应迭代器的接口,该操作返回ConcreteIterator的一个适当的实例

二. 迭代器模式的示例

以音乐播放为例来进行展示:

Iterator迭代器

代码语言:javascript
复制
package com.wangmengjun.tutorial.designpattern.iterator;

public interface MusicIterator {

  boolean hasNext();

  Music next();
}

Aggregate(聚合)

代码语言:javascript
复制
package com.wangmengjun.tutorial.designpattern.iterator;

public interface MusicCollection {

  void add(Music entity);

  void remove(Music entity);

  MusicIterator iterator();
}

ConcreteAggregate(具体聚合)

代码语言:javascript
复制
package com.wangmengjun.tutorial.designpattern.iterator;

import java.util.ArrayList;
import java.util.List;

public class AudioPlayer implements MusicCollection {

  private List<Music> musicList;

  public AudioPlayer() {
    musicList = new ArrayList<>();
  }

  @Override
  public void add(Music entity) {
    musicList.add(entity);
  }

  @Override
  public void remove(Music entity) {
    musicList.remove(entity);
  }

  @Override
  public MusicIterator iterator() {
    return new MusicIteratorImpl();
  }

  //ConcreteIterator(具体迭代器)
  private class MusicIteratorImpl implements MusicIterator {
    private int cursor;

    @Override
    public boolean hasNext() {
      return cursor < AudioPlayer.this.musicList.size();
    }

    @Override
    public Music next() {
      Music music = AudioPlayer.this.musicList.get(cursor);
      cursor++;
      return music;
    }

  }

}

Music类

代码语言:javascript
复制
package com.wangmengjun.tutorial.designpattern.iterator;

public class Music {

  private String name;

  private String singer;

  public Music(String name, String singer) {
    super();
    this.name = name;
    this.singer = singer;
  }

  /**
   * @return the name
   */
  public String getName() {
    return name;
  }

  /**
   * @param name the name to set
   */
  public void setName(String name) {
    this.name = name;
  }

  /**
   * @return the singer
   */
  public String getSinger() {
    return singer;
  }

  /**
   * @param singer the singer to set
   */
  public void setSinger(String singer) {
    this.singer = singer;
  }

  @Override
  public String toString() {
    return "Music [name=" + name + ", singer=" + singer + "]";
  }



}

测试一下:

代码语言:javascript
复制
package com.wangmengjun.tutorial.designpattern.iterator;

public class Main {

  public static void main(String[] args) {

    MusicCollection musicList = new AudioPlayer();
    musicList.add(new Music("吻別","张学友"));
    musicList.add(new Music("忘情水","刘德华"));
    musicList.add(new Music("过火","张信哲"));
    musicList.add(new Music("阳光总在风雨后","许美静"));

    /**
     * Music [name=吻別, singer=张学友]
       Music [name=忘情水, singer=刘德华]
           Music [name=过火, singer=张信哲]
           Music [name=阳光总在风雨后, singer=许美静]
     */
    MusicIterator iterator = musicList.iterator();
    while(iterator.hasNext()) {
      Music elem = iterator.next();
      System.out.println(elem);
    }
  }
}

输出結果:

代码语言:javascript
复制
Music [name=吻別, singer=张学友]
Music [name=忘情水, singer=刘德华]
Music [name=过火, singer=张信哲]
Music [name=阳光总在风雨后, singer=许美静]

这样,一个简单的迭代器模式示例就完成了。

三. 小结

优缺点

优点:

  • 迭代器模式简化了聚集的界面。迭代器具备了一个遍历接口,这样聚集的接口就不必具备遍历接口。
  • 每一个聚集对象都可以有一个或一个以上的迭代器对象,每一个迭代器的迭代状态可以是彼此独立的。因此,一个聚集对象可以同时有几个迭代在进行之中,以ArrayList为例,其内部就包含内部迭代Itr类和ListItr类。
代码语言:javascript
复制
  public ListIterator<E> listIterator(int index) {
        rangeCheckForAdd(index);
        return new ListItr(index);
    }

    /**
     * Returns a list iterator over the elements in this list (in proper
     * sequence).
     *
     * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
     *
     * @see #listIterator(int)
     */
    public ListIterator<E> listIterator() {
        return new ListItr(0);
    }
    
    public Iterator<E> iterator() {
        return new Itr();
    }

    /**
     * An optimized version of AbstractList.Itr
     */
    private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        ... ...
    }
    
    /**
     * An optimized version of AbstractList.ListItr
     */
    private class ListItr extends Itr implements ListIterator<E> {
    
            ... ...
    }
  • 由于遍历算法被封装在迭代器对象,因此,不必知道聚集对象的类型,就可以读取和遍历聚集对象。这样即便聚集对象的类型发生变化,也不会影响到客户端的遍历过程。

缺点:

  • 迭代器模式给客户端一个聚集被顺序化的错觉,因为大多数的情况下聚集的元素并没有确定的顺序,但是迭代必须以一定线性顺序进行。如果客户端误以为顺序是聚集本身具有的特性而过度依赖于聚集元素的顺序,很可能得出错误的结果。

参考

[1]. 阎宏. Java与模式.电子工业出版社

[2]. Erich Gamma. 设计模式-可复用面向对象软件的基础. 机械工业出版社.

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-04-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 孟君的编程札记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一. 迭代器模式的基本介绍
  • 二. 迭代器模式的示例
  • 三. 小结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档