图解设计模式之Iterator模式————一个一个遍历

1、Iterator模式

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

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

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

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

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

2、示例程序

    首先,让我们来看一段实现了Iterator模式的示例程序。这段示例程序的作用是将书(Book)放置到书架(BookShelf)中,并将书的名字按顺序显示出来。

Aggregate接口

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

public interface Aggregate {
    /**
     * 生成一个用于遍历集合的迭代器
     * @return
     */
    public abstract Iterator iterator();
}

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

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

Iterator接口

public interface Iterator {
    /**
     * 判断是否存在下一个元素
     * @return
     */
    public abstract boolean hasNext();

    /**
     *获取下一个元素
     * @return
     */
    public abstract Object next();

}

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

    hasNext方法的返回值是boolean类型的,其原因很容易理解。当集合中存在下一个元素时,该方法返回true,反之,返回false。hasNext方法主要用于循环终止条件。

    这里有必要说明一下next方法。该方法返回的类型是Object,这表明该方法返回的是集合中的一个元素。但是,next方法的作用并非仅仅如此。为了能够在下次调用next方法时正确地返回下一个元素,该方法还隐含着将迭代器移动至下一个元素的处理。

Book类

public class Book {
    private String name;

    public Book(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

Book类表示书的类,但是这个类的作用有限,他可以做的事情只有一件————通过getName方法获取书的名字。

BookShelf类

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;
    }

    @Override
    public Iterator iterator() {
        return new BookShelfIterator(this);
    }
} 

    BookShelf类是表示书架的类。由于需要将该类作为集合进行处理,因此他实现了Aggregate接口。这个书架中定义了books字段,他是Book类型的数组。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;
    }

    @Override
    public boolean hasNext() {
        return index < bookShelf.getLength() ? true : false;
    }

    @Override
    public Object next() {
        Book book = bookShelf.getBookAt(index);
        index++;
        return book;
    }
}

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

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

Main类

public class Main {
    public static void main(String[] args) {
        BookShelf bookShelf = new BookShelf(5);
        bookShelf.appendBook(new Book("Java"));
        bookShelf.appendBook(new Book("c++"));
        bookShelf.appendBook(new Book("c"));
        bookShelf.appendBook(new Book("sql"));
        bookShelf.appendBook(new Book("php"));
        Iterator iterator = bookShelf.iterator();
        while (iterator.hasNext()){
            Book book = (Book) iterator.next();
            System.out.println(book.getName());
        }
    }
}

这段程序首先设计了一个能容纳5本书的书架,然后添加了5本书。最后通过bookShelf.iterator()得到的iterator是用于遍历书架的Iterator实例。最后循环遍历输出书的名字。

下图是上面这段代码的运行结果


3、Iterator模式中的登场角色

    Iterator(迭代器) 

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

    ConcreteIterator(具体的迭代器)

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

    Aggregate(集合)

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

    ConcreteAggregate(具体的集合)

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

下图展示了Iterator模式的类图


4、扩展思路的要点

    不管实现如何变化,都可以使用 Iterator

     引入 Iterator 后可以将遍历与实现分离开来。设计模式的作用就是帮助我们编写可复用的类。所谓“可复用”,就是指将类实现为组件”,当一个组件发生改变时,不需要对其他的组件进行修改或是只需要很小的 即可应付。

    难以理解抽象类和接口

引入抽象类和接口是为了降低耦合度,如果只是用具体的类来解决问题,很容易导致类之间的强耦合,这些类也难以作为组件被再次利用。为了弱化类之间的强耦合,进而使得类更加容易作为组件被再次 利用,我们需要引入抽象类和接口。

猜你喜欢

转载自blog.csdn.net/Mr_Chenjie_C/article/details/80954667