图解设计模式(1) Iterator模式——— 一个一个遍历

1.1 Iterator模式

使用java语言显示数组arr中的元素时,我们可以使用下面这样的for循环语句遍历数组。

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

请注意这段代码中的循环变量i。该变量的初始值是0,然后会递增为1,2,3,。。。,程序则在每次i递增后都会输出arr[i]。我们在程序中会经常看到这样的for循环语句。

arr[0]  最开始的元素(第0 个元素)
arr[1]  下一个元素(第1 个元素)
           ┇
arr[i] (第i 个元素)
           ┇
arr[arr.length - 1]  最后一个元素

for语句中的i++的作用是让i的值在每次循环后自增1,这样就可以访问数组中的下一个元素、下下一个元素、再下下一个元素,也就实现了从头到尾逐一遍历数组元素的功能。

将这里的循环变量i的作用抽象化,通用化后形成的模式,在设计模式中称为Iterator模式。Iterator模式用于在数据集合中按照顺序遍历集合。英语单词Iterator有反复做某件事情的意思,汉语称为“迭代器”。我们将在本篇文章中学习Iterator模式。

1.2 示例程序

这段示例程序的作用是将书(Book)放置到书架(Bookshelf)中,并将书的名字按顺序显示出来。

在这里插入图片描述

Aggregate 接口

Aggregate 接口(代码清单 1-1)是所要遍历的集合的接口。实现了该接口的类将成为一个可以保存多个元素的集合,就像数组一样。Aggregate 有“使聚集”“集合”的意思。

在这里插入图片描述
类和接口的一览表:

名字说明
Aggregate表示集合的接口
Iterator遍历集合的接口
Book表示书的类
BookShelf表示书架的类
BookShelfIterator遍历书架的类
Main测试程序行为的类

Aggregate 接口(Aggregate.java)

public interface Aggregate {
    public abstract Iterator iterator();
}

在 Aggregate 接口中声明的方法只有一个——iterator 方法。该方法会生成一个用于遍历集合的迭代器。

想要遍历集合中的元素时,可以调用 iterator 方法来生成一个实现了 Iterator 接口的类的实例。

Iterator 接口(Iterator.java)

public interface Iterator {
    public abstract boolean hasNext();
    public abstract Object next();
}

这里我们声明了两个方法,即判断是否存在下一个元素的 hasNext 方法,和获取下一个元素的 next 方法。

hasNext 方法的返回值是 boolean 类型的,其原因很容易理解。当集合中存在下一个元素时,该方法返回 true ;当集合中不存在下一个元素,即已经遍历至集合末尾时,该方法返回 false。hasNext 方法主要用于循环终止条件。

这里有必要说明一下 next 方法。该方法的返回类型是 Object,这表明该方法返回的是集合中的一个元素。但是,next 方法的作用并非仅仅如此。为了能够在下次调用 next 方法时正确地返回下一个元素,该方法中还隐含着将迭代器移动至下一个元素的处理。说“隐含”,是因为 Iterator 接口只知道方法名。想要知道 next 方法中到底进行了什么样的处理,还需要看一下实现了 Iterator 接口的类(BookShelfIterator)。这样,我们才能看懂 next 方法的作用。

Book 类
Book 类是表示书的类。但是这个类的作用有限,它可以做的事情只有一件——通过 getName 方法获取书的名字。书的名字是在外部调用 Book 类的构造函数并初始化 Book 类时,作为参数传递给 Book 类的。

public class Book {
    private String name;
    public Book(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
}

BookShelf 类

BookShelf 类是表示书架的类。由于需要将该类作为集合进行处理,因此它实现了 Aggregate 接口。代码中的 implements Aggregate 部分即表示这一点。此外,请注意在 BookShelf 类中还实现了 Aggregate 接口的 iterator 方法。

public class BookShelf implements Aggregate {
    private Book[] books;
    private int last = 0;
    public BookShelf(int maxsize) {
        this.books = new Book[maxsize];
    }
    public Book getBookAt(int index) {
        return books[index];
    }
    public void appendBook(Book book) {
        this.books[last] = book;
        last++;
    }
    public int getLength() {
        return last;
    }
    public Iterator iterator() {
        return new BookShelfIterator(this);
    }
}

iterator 方法。该方法会生成并返回 BookShelfIterator 类的实例作为 BookShelf 类对应的 Iterator。当外部想要遍历书架时,就会调用这个方法。

BookShelfIterator 类

public class BookShelfIterator implements Iterator {
    private BookShelf bookShelf;
    private int index;
    public BookShelfIterator(BookShelf bookShelf) {
        this.bookShelf = bookShelf;
        this.index = 0;
    }
    public boolean hasNext() {
        if (index < bookShelf.getLength()) {
            return true;
        } else {
            return false;
        }
    }
    public Object next() {
        Book book = bookShelf.getBookAt(index);
        index++;
        return book;
    }
}

因为 BookShelfIterator 类需要发挥 Iterator 的作用,所以它实现了 Iterator 接口。

bookShelf 字段表示 BookShelfIterator 所要遍历的书架。index 字段表示迭代器当前所指向的书的下标。

构造函数会将接收到的 BookShelf 的实例保存在 bookShelf 字段中,并将 index 初始化为 0。

hasNext 方法是 Iterator 接口中所声明的方法。该方法将会判断书架中还有没有下一本书,如果有就返回 true,如果没有就返回 false。而要知道书架中有没有下一本书,可以通过比较 index 和书架中书的总册数(bookShelf.getLength() 的返回值)来判断。

next 方法会返回迭代器当前所指向的书(Book 的实例),并让迭代器指向下一本书。它也是 Iterator 接口中所声明的方法。next 方法稍微有些复杂,它首先取出 book 变量作为返回值,然后让 index 指向后面一本书。

如果与本章开头的 for 语句来对比,这里的“让 index 指向后面一本书”的处理相当于其中的 i++,它让循环变量指向下一个元素。

Main 类

public class Main {
    public static void main(String[] args) {
        BookShelf bookShelf = new BookShelf(4);
        bookShelf.appendBook(new Book("Around the World in 80 Days"));
        bookShelf.appendBook(new Book("Bible"));
        bookShelf.appendBook(new Book("Cinderella"));
        bookShelf.appendBook(new Book("Daddy-Long-Legs"));
        Iterator it = bookShelf.iterator();
        while (it.hasNext()) {
            Book book = (Book)it.next();
            System.out.println(book.getName());
        }
    }
}

运行结果:
在这里插入图片描述

1.3 Iterator 模式中的登场角色

  • Iterator(迭代器)

该角色负责定义按顺序逐个遍历元素的接口(API)。在示例程序中,由 Iterator 接口扮演这个角色,它定义了 hasNext 和 next 两个方法。其中,hasNext 方法用于判断是否存在下一个元素,next 方法则用于获取该元素。

  • ConcreteIterator(具体的迭代器)

该角色负责实现 Iterator 角色所定义的接口(API)。在示例程序中,由 BookShelfIterator 类扮演这个角色。该角色中包含了遍历集合所必需的信息。在示例程序中,BookShelf 类的实例保存在 bookShelf 字段中,被指向的书的下标保存在 index 字段中。

  • Aggregate(集合)

该角色负责定义创建 Iterator 角色的接口(API)。这个接口(API)是一个方法,会创建出“按顺序访问保存在我内部元素的人”。在示例程序中,由 Aggregate 接口扮演这个角色,它里面定义了 iterator 方法。

  • ConcreteAggregate(具体的集合)

该角色负责实现 Aggregate 角色所定义的接口(API)。它会创建出具体的 Iterator 角色,即 ConcreteIterator 角色。在示例程序中,由 BookShelf 类扮演这个角色,它实现了 iterator 方法。

Iterator 模式的类图
在这里插入图片描述

1.4 相关的设计模式

  • Visitor 模式

Iterator 模式是从集合中一个一个取出元素进行遍历,但是并没有在 Iterator 接口中声明对取出的元素进行何种处理。

Visitor 模式则是在遍历元素集合的过程中,对元素进行相同的处理。

在遍历集合的过程中对元素进行固定的处理是常有的需求。Visitor 模式正是为了应对这种需求而出现的。在访问元素集合的过程中对元素进行相同的处理,这种模式就是 Visitor 模式。

  • Composite 模式

Composite 模式是具有递归结构的模式,在其中使用 Iterator 模式比较困难。

  • Factory Method 模式

在 iterator 方法中生成 Iterator 的实例时可能会使用 Factory Method 模式。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胡小冰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值