设计模式之——迭代器模式

参考了https://blog.csdn.net/lierming__/article/details/79620577的代码,图片和基本讲解(懒得打了)
都来自于《图解设计模式》——结城浩 著

Iterator模式

  • Iterator在英文中有反复做某事的意思,Iterator模式用于在数据集合中按照顺序遍历集合。
  • 迭代器(Iterator)模式,又叫做游标(Cursor)模式。GOF给出的定义为:提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象的内部细节。

示例程序

这段程序的作用是将书(Book)放到书架(BookShelf)上,并将书名按顺序显示出来。
示例程序的示意图:
这里写图片描述
示例程序的类图:
这里写图片描述
Aggregate 接口:
是所要遍历的集合的接口。实现了该接口的类将成为一个可以保存多个元素的集合

/*
 * 该接口中声明的方法只有一个-----iterator 方法。该方法会生成一个用于
 * 遍历集合的迭代器
 */
public interface Aggregate {
public abstract Iterator iterator();


}

Iterator 接口:
Iterator接口用于遍历集合中的元素

/*
 * 该接口用于遍历集合中的元素,其作用相当于循环语句中的循环变量
 */


public interface Iterator {
public abstract boolean hasNext();   //判断是否存在下一个元素的hasNext 方法 ,该方法主要用于循环终止条件
public abstract Object next();       //获取下一个元素的 next 方法


}

Book 类:

是BookShelf的成员变量,BookShelf知道他

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

//获取书的名字
public String getName(){
return name;
}


}

BookShelf 类:

表示书架的类,由于需要作为集合进行处理,所以实现了Aggregate接口,并且实现了Aggregate接口的iterator方法。

public class BookShelf implements Aggregate{
private Book[] books;               
private int last = 0;                   //书架上书的数量
public BookShelf(int maxsize){          //生成 BookShelf 实例时指定 books 数组的大小 
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;
}

//获取遍历该书架的  Iterator 实例。当想在外部遍历书架时,就会调用该方法
public Iterator iterator(){           
return new BookShelfIterator(this);
}


}

iterator()方法会生成并返回BookShelfIterator类的实例作为BookShelf类对应的迭代器
BookShelfIterator 类:

public class BookShelfIterator implements Iterator{
private BookShelf bookShelf;                    //所要遍历的书架
private int index;                              //表示迭代器当前所指向的书的下标

public BookShelfIterator(BookShelf bookShelf){
this.bookShelf = bookShelf;
this.index = 0;
}
/*
* hasNext ()  方法会判断书架中还有没有下一本书,如果有就返回 true ,
* 如果没有就返回 false 。而要知道书架中有没有下一本书,可以通过比较index
* 和书架中书的总册数(bookShelf.getLength())来判断。
* 
*/
public boolean hasNext(){
if(index < bookShelf.getLength()){
return true;
}else{
return false;
}

}
/*
* next() 方法会返回迭代器当前所指向的书(Book 的实例),并让迭代器指向下一本书。
* 
*/
public Object next(){
Book book = bookShelf.getBookAt(index);
index++;
return book;
}


}

BookShelf类需要发挥迭代器的作用,所以实现了Iterator接口。
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());

}

}


}

运行结果
这里写图片描述

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模式,而不用简单的foreach循环来遍历呢?
    Iteraror模式是将遍历和实现分离开来的

看以下代码

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

如果你想用for each循环来遍历,是一定要用到bookshelf的,实现如下

Book[] b = BookShelf.books;
for( book c: b){
    System.out.println(c.getName());
}

如果你不用数组来管理Book,而是用别的集合,以上代码会怎样呢?

  • 而Iterator模式的while循环并不依赖于BookShelf的实现,只要BookShelf实现Aggregate接口,能正确的返回Iterator实例(即hasnext和next都正常),即使不修改while的代码,也可以正常工作。
  • 设计模式的作用就是帮助我们编写可复用的类。所谓“可复用”,就是指将类实现为“组件”,当一个组件发生改变时,不需要对其他的组件进行修改或是只需要很小的即可应付。
  • 这也就是为什么在示例程序中Iterator方法返回的是Iterator而不是BookShelfIterator类型了。

    难以理解抽象类和接口——–>引入抽象类和接口是为了降低耦合度
    如果只是用具体的类来解决问题,很容易导致类之间的强耦合,这些类也难以作为组件被再次利用。为了弱化类之间的强耦合,进而使得类更加容易作为组件被再次利用,我们需要 引入抽象类和接口。
    容易弄错“下一个”
    在Iterator 模式的实现中,next 方法是 “返回当前的元素,并指向下一个元素”
    还容易弄错“最后一个”
    hasNext 可以理解成:“确认接下来是否可以调用 next 方法”的方法就可以了。
    多个Iterator
    “将遍历功能置于 Aggregate 角色之外 ”是 Iterator 模式的一个特征。
    迭代器种类的多种多样
    在示例程序中展示的 Iterator 类只是很简单地从前往后遍历集合。其实,遍历的方法有是多种多样的。

                  **** 从最后开始向前遍历
    
                  **** 既可以从前向后遍历,也可以从后往前遍历(既有 next 方法也有 previous 方法)
    
                  **** 指定下标进行“跳跃式”遍历
    

即,根据你的基本思想可以自己写Iterator接口,然后在ConcreteAggregate中具体实现,(具体怎么实现,什么算法都可以),这也体现了Iterator模式将遍历和实现分离开来的思想

总结:简单地说,迭代器就是一个用于对集合进行遍历的实现,优点在于,实现和遍历分离,不在乎容器内部原理(采用数组啊还是哈希表啊blabla)。

猜你喜欢

转载自blog.csdn.net/weixin_38719347/article/details/81273445
今日推荐