迭代器模式

迭代器模式

1、前言

类似于Java语言中的for循环遍历一个一个数组,如下面这段程序:

for(int i = 0; i < arr.length;i++){
    System.out.println(arr[i]);
}

将循环变量元素i抽象化的模式就称为迭代器模式(Iterator模式)。迭代器模式可以按照指定的顺序规则遍历指定的集合。

2、示例程序

2.1、UML类图

在这里插入图片描述

  • 类和接口一览表

    类或接口名说明
    Aggregate一个接口,表明实现该接口的类是一个集合类,并提供一个可以遍历该集合的迭代器
    Iterator遍历集合的接口
    BookShelf表示书架的类
    BookShelfIterator遍历书架的类
    Book表示书的类
    Main测试程序

2.2、示例程序

  • Aggregate接口

    Aggregate接口会生成一个遍历集合的迭代器。

    示例程序:

    /**
     * 表明实现本接口的类是一个集合类
     */
    public interface Aggregate {
       /**
        * 获取能遍历实现类集合的迭代器
        * @return
        */
       Iterator iterator();
    }
    
  • Iterator接口

    Iterator接口用于遍历集合中的元素。其中,hasNext()方法用于判断集合中是否还有元素;next()方法用于获取集合中当前索引处的元素,并将索引指向下一处。

    示例程序:

    public interface Iterator {
       /**
        * 是否还有下一元素
        * @return
        */
       boolean hasNext();
    
       /**
        * 取出下一元素
        * @return
        */
       Object next();
    }
    
  • BookShelf类

    BookShelf类实现了Aggregate接口,实现了iterator方法,并还提供了遍历集合所需要的必要方法。

    示例程序:

    public class BookShelf implements Aggregate{
        private Book[] books;
       private int last = 0;
    
       /**
        * 初始化书架大小
        * @param size
        */
       public BookShelf(int size) {
          this.books = new Book[size];
       }
    
       /**
        * 向书架放书
        * @param book
        */
       public void appendBook(Book book){
          this.books[last] = book;
          last++;
       }
    
       /**
        * 获取指定索引处的书籍
        * @param index
        * @return
        */
       public Book getBookAt(int index){
          return this.books[index];
       }
    
       /**
        * 返回书架容量大小
        * @return
        */
       public int getLength(){
          return last;
       }
    
       /**
        * 返回遍历本书架的一个迭代器
        * @return
        */
       @Override
       public Iterator iterator() {
          return new BookShelfIterator(this);
       }
    }
    
  • BookShelfIterator类

    BookShelfIterator类实现了Iterator接口,专门用于遍历BookShelf集合中的元素。

    示例程序:

    public class BookShelfIterator implements Iterator {
       private BookShelf bookShelf;
       private int index = 0;
    
       public BookShelfIterator(BookShelf bookShelf) {
          this.bookShelf = bookShelf;
       }
    
       /**
        * 判断书架是否还有书
        * @return
        */
       @Override
       public boolean hasNext() {
          if(index < bookShelf.getLength()){
             return true;
          }
          return false;
       }
    
       /**
        * 获取下一个元素
        * @return
        */
       @Override
       public Object next() {
          Book book = bookShelf.getBookAt(index);
          index++;
          return book;
       }
    }
    
  • Book类

    public class Book {
       private String name;
    
       public Book(String name) {
          this.name = name;
       }
    
       public String getName() {
          return name;
       }
    }
    
  • 测试类Main

    public class App {
       public static void main(String[] args) {
          BookShelf bookShelf = new BookShelf(5);
          // 向书架添加书籍
          bookShelf.appendBook(new Book("Java从入门到入土"));
          bookShelf.appendBook(new Book("三国演义"));
          bookShelf.appendBook(new Book("红楼梦"));
          bookShelf.appendBook(new Book("水浒传"));
          bookShelf.appendBook(new Book("西游记"));
          Iterator iterator = bookShelf.iterator();
          // 遍历书架
          while (iterator.hasNext()){
             Book next = (Book) iterator.next();
             System.out.println(next.getName());
          }
       }
    }
    
  • 测试结果

在这里插入图片描述

3、迭代器模式中的角色

  • Iterator(迭代器)

    该角色负责定义迭代器的扫描规则及获取元素的方法。示例程序中,由Iterator接口扮演这个角色。

  • Aggregate(集合)

    该角色负责定义可以返回遍历本集合的迭代器的方法。在示例程序中,由Aggregate接口扮演这个角色。

  • ConcreteIterator(具体的迭代器)

    该角色负责实现Iterator角色的定义的方法,该角色还要提供遍历集合所必要的信息,比如书架–bookShelf、遍历索引–index。在示例程序中,由BookShelfIterator类扮演此角色。

  • ConcreteAggregate类

    该角色负责实现Aggregate接口中的方法,它会返回具体的迭代器。在示例程序中,由BookShelf类扮演此角色。

迭代器模式的UML类图

在这里插入图片描述

4、拓展思路

4.1、不管实现如何,都可以使用Iterator

迭代器的作用就是用来遍历集合的,那为什么不直接用for循环遍历集合呢,还非得多此一举?

迭代器的一大作用就是它可以让集合的遍历与集合的实现进行分离,请看如下代码:

// 遍历书架
while (iterator.hasNext()){
   Book next = (Book) iterator.next();
   System.out.println(next.getName());
}

迭代器遍历集合的代码是没有BookShelf这个类的,也即迭代器遍历是不依赖于集合类的。因此如果后期集合类存储元素的容器不使用数组,改为使用List集合了,那么上面这段遍历集合的代码仍然可以使用。这也就体现了一个类作为一个组件的可复用性–这个组件的修改,不会影响或者说很少影响其他的组件。

4.2、面向接口(抽象)编程

可以看到iterator()方法在返回迭代器时,返回类型是Iterator,而不是BookShelfIterator。这表明这段程序强调的是要使用Iterator的方法而不是BookShelfIterator中特有的方法,且这样可以弱化类之间的耦合程度,提升这段程序的可用性。

4.3、迭代器中的方法

1、next()方法很容易让人搞混,到底是返回当前元素,还是返回下一个元素呢?其实next()方法是返回当前元素,并指向下一元素。

2、hasNext()方法。这个方法也容易搞混,当索引遍历至最后一个元素时,这时该方法是返回true还是返回false呢?答案是会返回true。它并不是判断当前集合中是否还有下一个元素,他是判断当前集合是否还允许再次调用next()方法。因此当next()方法返回元素后,再次调用hasNext()方法便返回false。

5、总结

迭代器模式就是用于遍历集合中的元素,其一大好处是将集合的遍历与集合的实现方式进行了分离,不论集合存储元素的方式如何变化,集合的遍历方式都不会受到影响。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值