设计模式:迭代器模式
设计模式:迭代器模式
一、前言
设计模式有很多,最典型的是GoF的23种设计模式,听起来很多,其实大部分我们都是见过的,按照常见度来分,最常用的差不多是六七个吧,因此,我们在学习的时候应该有轻重缓急之分,不能一视同仁,而应该抓住重点,将一些最常用的设计模式吃透了,那么我们在遇到一个实际问题的时候就能根据问题的需要来进行相应的取舍。学习是一个循环往复的过程,没有学过一次不再接触就能掌握的,一定要反复的记忆,反复的练习,不断地提炼,不断地提高,没有复习的学习就是参观,没有预习的学习就是做梦,没有提升的学习就是浪费时间。
二、迭代器模式
什么叫做迭代器,我们可能在C++的STL标准模板库或者在Java中见过iterator这个东西,所谓“迭代”就是按照一定的次序或顺序进行重复操作,这个操作可以是遍历也可以是反复的计算,而迭代器就是按照一定的顺序对元素进行遍历的过程。理解到这个程度,我们可能非常的奇怪,因为我们完全可以使用一个for循环来完成这样的操作,又何必大费周章的来一个迭代器来遍历呢?!这就涉及到软件设计中最重要的一个原则了,那就是高内聚,低耦合。当我们使用for循环来完成遍历操作的时候代码中有着大量的耦合,当我们需要修改代码的时候,不能做到少改甚至不改遍历的代码,而迭代器可以做到,这为代码的可移植性、可扩展性等特性奠定了基础。我们可以看到设计模式大多数是把简单的问题给搞复杂了,但是这种复杂恰恰是为了以后设计和扩展的简单。正如没有规划的盖一座房子,很快就盖成了一座房子,可是因为没有考虑到房子的方位、地基、以后的扩展、居住的舒适,改出来的房子最后不能进行扩展并且不符合力学的美感和力感,最终只能重新拆掉重建,所以学习设计模式的时候最好看一些建筑方面的设计,明白全局观的重要性。
废话少说,直接上代码(talk is cheap,let's show code!)
Book 类的定义:
1 package zyr.dp.iterator; 2 3 public class Book { 4 private String name; 5 6 public Book(String name) { 7 this.name = name; 8 } 9 10 public String getName() { 11 return name; 12 } 13 }
Aggregate 接口的定义:
1 package zyr.dp.iterator; 2 3 public interface Aggregate { 4 public abstract Iterator iterator(); 5 }
BookShelf 类的定义:
1 package zyr.dp.iterator; 2 3 public class BookShelf implements Aggregate { 4 private Book[] books; 5 int pointer=0; 6 public BookShelf(int max_size){ 7 books=new Book[max_size]; 8 } 9 public void appendBook(Book book){ 10 books[pointer]=book; 11 pointer++; 12 } 13 public Book findBookAt(int index){ 14 return books[index]; 15 } 16 public int getLength(){ 17 return pointer; 18 } 19 public Iterator iterator(){ 20 return new BookShelfIterator(this); 21 } 22 }
Iterator 接口的定义:
1 package zyr.dp.iterator; 2 3 public interface Iterator { 4 public abstract boolean hasNext(); 5 public abstract Object next(); 6 }
BookShelfIterator 类的定义:
1 package zyr.dp.iterator; 2 3 public class BookShelfIterator implements Iterator { 4 5 BookShelf bookShelf; 6 int index; 7 public BookShelfIterator(BookShelf bookShelf){ 8 this.bookShelf=bookShelf; 9 index=0; 10 } 11 public boolean hasNext() { 12 if(index<this.bookShelf.getLength()){ 13 return true; 14 } 15 return false; 16 } 17 18 public Object next() { 19 return bookShelf.findBookAt(index++); 20 } 21 }
Main 函数:
1 package zyr.dp.iterator; 2 3 public class Main { 4 5 public static void main(String[] args) { 6 7 Book book1 = new Book("朝花夕拾"); 8 Book book2 = new Book("围城"); 9 Book book3 = new Book("遮天"); 10 Book book4 = new Book("寻秦记"); 11 Book book5 = new Book("骆驼祥子"); 12 13 BookShelf bookShelf = new BookShelf(5); 14 15 bookShelf.appendBook(book1); 16 bookShelf.appendBook(book2); 17 bookShelf.appendBook(book3); 18 bookShelf.appendBook(book4); 19 bookShelf.appendBook(book5); 20 21 Iterator it= bookShelf.iterator(); 22 while(it.hasNext()){ 23 Book book=(Book)it.next(); 24 System.out.println("书的名字为《"+book.getName()+"》"); 25 } 26 } 27 }
运行结果:
三、分析
在上面我们的程序中,有着很多值得说明的地方,首先是类、接口的结构,我们可以使用下面的图来表达,从图中我们可以看出,最核心的是两个对象,一个是书架这样的一个书的集合books[],代表了需要遍历的元素;另一个就是迭代器,好像一个工具,用到的时候将this对象代指的书架集合放里面,进行遍历,不需要的时候束之高阁。同时为什么会有接口呢,其实接口的作用是为了降低耦合度,在main函数中,我们使用的是Iterator这个接口来定义的引用,而不是BookShelfIterator,这样做的好处是完全屏蔽了内部的细节,在用户使用的时候,完全不知道BookShelfIterator的存在。
引入迭代器之后,可以将元素的遍历和实现分离开来,如下面的代码中的while循环,没有依赖与BookShelf的实现,没有使用BookShelf的其他方法,只是用了迭代器中hasNext和next方法。可复用指的是将一个类作为一个组件,当一个组件改变时,不需要对其他组件进行修改或者只进行少量的修改就可以实现修改后的功能。同样的Iterator it= bookShelf.iterator();面向接口编程,便于程序的修改和维护。
1 Iterator it= bookShelf.iterator(); 2 while(it.hasNext()){ 3 Book book=(Book)it.next(); 4 System.out.println("书的名字为《"+book.getName()+"》"); 5 }
同样的,迭代器的种类非常多,我们可以根据遍历的次序进行设计,来实现相应的功能。从该设计模式中我们可以看到接口的应用,面向接口编程的概念,以及元素的遍历与实现分离,实现了高内聚和低耦合。