GOF设计模式——Iterator模式

         Iterator,自然而然想到的是用于集合遍历的迭代器Iterator,没错Iterator模式就是指这个意思。

        先来看一段代码:

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

      上面是编程里面很常见的遍历数组的用法,假如我不直接操作array对象,然后将用于表示下标的 i 抽象化,通用化,将遍历的动作交给迭代器,那么这种模式就叫做Iterator模式。

        举一个示例,有一个书架和一些书,每一本书作为一个个体(实例),书架可以理解为这些个体的集合。

介绍一下上面的各个“东西”:

Aggregate:一个集合接口,凡是实现这个接口的iterator方法,就具有集合的功能;

Iterator:一个具有遍历功能的迭代器接口,里面定义了迭代需要的方法;

BookShelf:集合的具体实现类;

BookShelfIterator:迭代器接口的具体实现类;

Book:个体类。

1、Aggregate接口定义:

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

2、Iterator接口:

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

里面很简单,只定义了两个方法:hasNext和next。使用过集合迭代器的小伙伴都知道,hasNext用于判断是否存在元素,next获取当前元素的同时,将下标指向下一个元素。

3、BookShelf类定义

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

构造方法根据参数创建指定大小的Book数组,appendBook用于给数组添加元素,getLength获取当前数组长度(正确来说是当前数组最后一个元素的下标+1),另外,还实现了Aggregate的抽象方法iterator(),上面也提及到,只要一个类实现了Aggregate接口,就具有集合的功能,即遍历功能,在这里,只是用于创建迭代器的实现类BookShelfIterator,遍历的具体功能交给BookShelfIterator实现类去实现。

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

很简单,构造方法里将BookShelf对象作为参数,当前属性指向BookShelf对象,用于操作获取BookShelf元素,以及BookShelf长度。hashNext的实现逻辑只是对BookShelf对象的长度做一个判断,如果当前下标小于BookShelf长度,那么就返回true,否则,返回false。next方法,除了返回指定下标元素之外,还将下标向后推移了一位,即next实现了两个功能。

5、Book类定义

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

至于测试方法,这里不写出来了。

        我们就会发现,开头那段for代码里面的i++,就相当于next()方法里面的index++操作,都是用于指向下一位元素。上面代码的实现效果相当于ArrayList,不过BookShelf这个集合类这样子写,是会出问题的,ArrayList对象是可以“无限”添加元素,但是BookShelf最大只能添加maxsize个元素,所以可以进行改进。

改进后的BookShelf类:

public class BookShelf implement Aggregate{
    private List Books;
 
    public BookShelf(int initialsize){
        books = new ArrayList(initialsize);
    }
 
    public Book getBookAt(int index){
        return (Book)books.get(index);
    }
 
    public void appendBook(Book book){
        books.add(book);
    }
 
    public int getLength(){
        return books.size();
    }
 
    public Iterator iterator(){
        return new BookShelfIterator(this);
    }
 
}

至于为什么要使用Iterator呢?一个重要原因是,可以将遍历与实现分离开来。对BookShelf对象进行遍历的时候,会用到下面代码:

Iterator it = bookShelf.iterator();
while(it.hasNext()){
    Book book = (Book)it.next();
    System.out.println(book.getName());
}

遍历的过程,根本没有使用过BookShelf类的方法,完全不需要理会BookShelf的实现,也不知道BookShelf怎么实现,但是Iterator知道,所以只需要调用Iterator的方法就可以实现遍历BookShelf集合的效果。这样设计的好处就是,可以根据的实际业务需求来增加遍历的功能,使得原有的代码不改动或少改,达到一个低耦合的效果。

posted @ 2019-01-27 15:31  KamShing  阅读(202)  评论(0编辑  收藏  举报