设计模式:Iterator模式

正常通过for循环遍历一个数组的时候,循环变量那个index,如果将它抽象化形成一种模式就是Iterator模式,也就是迭代器模式

比如要创建一个书架,上架几本新书,Java,Python,Perl和Shell,结束之后还要遍历这个书架上的书籍

那么要实现存书和遍历两个功能,肯定首先有书和书架两个类,上架书只需要书架不停append各种书的实例即可,而遍历似乎直接for循环就可以直接输出

这里添加接口,通过Iterator模式迭代器来实现;下面的例子就不考虑java.lang里的,先说明Iterator模式

类和接口如下

Book:书籍类

Aggregate:集合的接口

Iterator:遍历接口的接口

BookShelf:书架类

BookShelfIterator:遍历书架的类

Main:main

先定义一个Iterator接口,可以理解为一个迭代器,用于遍历集合中的元素,这里就自定义两个简单抽象方法,用的比较多的

package iterator;

/**
* Copyright (C), 2014-2018, maoxiaomeng.com
* FileName: Iterator
* Author: lihui
* Date: 2018/4/27 21:33
*/

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

hasNext判断是否存在下一个元素;next获取下一个元素

然后定义一个Aggregate接口,里面声明一个iterator方法,返回一个迭代器

package iterator;

/**
* Copyright (C), 2014-2018, maoxiaomeng.com
* FileName: Aggregate
* Author: lihui
* Date: 2018/4/27 21:30
*/

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

因此只要是想遍历集合,就可以调用iterator方法来生成一个实现了Iterator接口的类实例,进而进行遍历;可以参考java.lang里的iterator方法

接着就是定义书籍Book类,实例化书籍对象,这个没啥好说的

package iterator;

/**
* Copyright (C), 2014-2018, maoxiaomeng.com
* FileName: Book
* Author: lihui
* Date: 2018/4/27 21:45
*/

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

public String getName() {
return name;
}
}

然后就是书架BookShelf类,它除了正常的初始化,添加书籍之外,还要实现Aggregate接口,因为既然是要遍历书架,那么就得生成一个遍历书架上所有书籍的迭代器,实现接口Aggregate的iterator方法,那么如果想要遍历书架,调用BookShelf类的该方法即可,与BookShelf类其它成员不相干

package iterator;

/**
* Copyright (C), 2014-2018, maoxiaomeng.com
* FileName: BookShelf
* Author: lihui
* Date: 2018/4/27 21:47
*/

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

实现Aggregate接口的iterator方法,生成的是一个BookShelf相关的迭代器,也就是具体遍历的实现方式

因为上面iterator方法已经有了一个迭代器接口,那么BookShelf通过调用该方法,进入到了具体的迭代器类BookShelfIterator来实现Iterator接口完成具体便利功能

package iterator;

/**
* Copyright (C), 2014-2018, maoxiaomeng.com
* FileName: BookShelfIterator
* Author: lihui
* Date: 2018/4/27 21:59
*/

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() {
if (index < bookShelf.getLength()) {
return true;
} else {
return false;
}
}

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

这里传了一个具体的BookShelf类对象,然后进行实例化BookShelfIterator,说明是为了遍历传入对象;next方法返回的是当前指向的book实例进行返回,但是在返回之前指向了下一个实例

最后就是测试代码,添加main

package iterator;

/**
* Copyright (C), 2014-2018, maoxiaomeng.com
* FileName: Main
* Author: lihui
* Date: 2018/4/27 22:03
*/

public class Main {
public static void main(String[] args) {
BookShelf bookShelf = new BookShelf(4);
bookShelf.appendBook(new Book("Java"));
bookShelf.appendBook(new Book("Python"));
bookShelf.appendBook(new Book("Perl"));
bookShelf.appendBook(new Book("Shell"));
Iterator it = bookShelf.iterator();
while (it.hasNext()) {
Book book = (Book)it.next();
System.out.println(book.getName());
}
}
}

创建一个书架,然后分别放上Java,Python,Perl,Shell四本书,获取遍历该书架的Iterator迭代器,最后一本一本地遍历输出

根据上述例子,可以看出Iterator模式里面的一些角色:

迭代器(Iterator):定义了按顺序来遍历元素的接口;也就是这个例子里的Iterator接口,定义了hasNext和next两个抽象方法

具体迭代器(Concretelterator):实现了迭代器(Iterator)所定义的接口;也就是这个例子里的BookShelfIterator类

集合(Aggregate):定义创建迭代器(Iterator)的接口;也就是这个例子里的Aggregate接口

具体集合(ConcreteAggregate):实现了集合(Aggregate)所定义的接口;也就是这个例子里的BookShelf类

 

有了上面一大堆,通过接口生成迭代器,然后遍历,的确可以通过for循环来返回,但是通过Iterator模式,可以将遍历和实现分开,从main最后的while可以看到,没有依赖BookShelf的实现,因此无论BookShelf如何变化,只要实现的iterator方法能够生成具体Iterator实例,对遍历没有任何影响

所以对于调用者来说,不管BookShelf里怎么变,只需要通过iterator方法提供给调用者一个迭代器,不需要其它任何东西,就能实现遍历功能

上面例子在每次创建BookShelf实例的时候,都要指明数组长度,不利于实际书架的操作,假如修改为ArrayList,只需要将BookShelf里书架的相关实现修改成List即可,对于遍历的实现,不需要进行任何修改

package iterator;

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

/**
* Copyright (C), 2014-2018, maoxiaomeng.com
* FileName: BookShelf
* Author: lihui
* Date: 2018/4/27 21:47
*/

public class BookShelf implements Aggregate {
private List<Book> books;

public BookShelf() {
books = new ArrayList<Book>();
}

public Book getBookAt(int index) {
return books.get(index);
}

public void appendBook(Book book) {
books.add(book);
}

public int getLength() {
return books.size();
}

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

main里创建BookShelf实例也不需要指定长度 

发表评论