被说了很多遍的设计模式---迭代器模式

来源:互联网 发布:手机网络视频直播软件 编辑:程序博客网 时间:2024/05/02 04:52

[把你的理性思维慢慢变成条件反射]

本文,我们讲介绍迭代器模式,文章主题结构与上文一致。惯例,先来看看我们示例工程的环境:

操作系统:win7 x64

其他软件:eclipse mars,jdk8

-------------------------------------------------------------------------------------------------------------------------------------

经典问题:

某一个特定集合(聚合)的遍历(迭代)

思路分析:

要点一:所谓遍历,就是要无一例外的全部访问。

要点二:遍历(迭代)只讲全面,而忽略顺序。即,任何位置的元素都可以作为起点。

示例工程:


迭代器模式模板代码:


创建Aggregate.java文件,具体内容如下:

package com.csdn.ingo.gof_Iterator;import java.util.ArrayList;import java.util.List;public abstract class Aggregate {protected List<Object> objects = new ArrayList<Object>();public Aggregate(List objects){this.objects = objects;}public void add(Object obj){this.objects.add(obj);}public void remove(Object obj){this.objects.remove(obj);}public List getObjects(){return this.objects;}public abstract Iterator createIterator();}
创建ConcreteAggregate.java文件,具体内容如下:

package com.csdn.ingo.gof_Iterator;import java.util.ArrayList;import java.util.List;public class ConcreteAggregate extends Aggregate {public ConcreteAggregate(List objects) {super(objects);// TODO Auto-generated constructor stub}private List<Object> items = new ArrayList<Object>();public int Count;@Overridepublic Iterator createIterator() {return new ConcreteIterator(this);}public int getCount() {return items.size();}public void setCount(int count) {Count = count;}}
创建ConcreteIterator.java文件,具体内容如下:

package com.csdn.ingo.gof_Iterator;import java.util.List;public class ConcreteIterator extends Iterator {private ConcreteAggregate aggregate;private List aggregates;private int cursor1;private int cursor2;public ConcreteIterator (ConcreteAggregate aggregate){this.aggregate = aggregate;this.aggregates = aggregate.getObjects();cursor1 = 0;cursor2 = aggregates.size()-1;}@Overridepublic boolean isFirst() {return (cursor2==-1);}@Overridepublic void previous() {if(cursor2>-1){cursor2--;}}@Overridepublic boolean isLast() {return (cursor1==aggregates.size());}@Overridepublic Object getCurrentItem() {return aggregates.get(cursor1);}@Overridepublic Object getPreviousItem() {return aggregates.get(cursor2);}@Overridepublic void next() {if(cursor1<aggregates.size()){cursor1++;}}}
创建Iterator.java文件,具体内容如下:

package com.csdn.ingo.gof_Iterator;public abstract class Iterator {    public abstract boolean isFirst();    public abstract void next();    public abstract void previous();    public abstract boolean isLast();    public abstract Object getCurrentItem();    public abstract Object getPreviousItem();}
创建Window.java文件,具体内容如下:

package com.csdn.ingo.gof_Iterator;import java.util.ArrayList;import java.util.List;public class Window {public static void main(String[] args) {List products =new ArrayList();products.add("AAA");products.add("BBB");products.add("CCC");products.add("DDD");products.add("EEE");Iterator iterator;Aggregate list;list = new ConcreteAggregate(products);iterator = list.createIterator();System.out.println("---正向遍历---");while(!iterator.isLast()){System.out.println(iterator.getCurrentItem()+",");iterator.next();}System.out.println("------------");System.out.println("---反向遍历---");while(!iterator.isFirst()){System.out.println(iterator.getPreviousItem()+",");iterator.previous();}}}
【上面的代码直接看的话,可能有难度。先把代码提供给各位看官是希望现将代码运行起来,观察结果。下面我们介绍相关的概念与原理】

模式总结:

迭代器模式结构图:


迭代器模式:

提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示

组成部分:

Iterator(抽象迭代器):定义了访问和遍历元素的接口,声明了用于遍历元素的方法。

ConcreteIterator(具体迭代器):实现抽象迭代器,完成对聚合对象的遍历,并且通过游标记录当前遍历的索引位置。

Aggregate(抽象聚合类):用于存储和管理元素对象,声明一个createIterator()方法用于创建一个迭代器对象。

ConcreteAggregate(具体聚合类):实现了抽象聚合类,返回一个具体的迭代器实例。

特别提醒:迭代器模式应用到了工厂方法模式的设计方法。【详情参考:http://blog.csdn.net/abcd898989/article/details/52859560】

JDK的内置迭代器:【以下内容来自其他博文与JDK源码】

在java中,常见的list与set都继承或者实现了java.util.Collection接口。

Collection的具体内容如下:


我们看到除了add,remove方法外,还提供了iterator方法,用于返回一个迭代器对象。具体的java聚合类可以通过实现该iterator方法返回一个具体的迭代器对象。

JDK中定义的抽象迭代器接口内容如下:


以上方法的官方解释如下:



测试代码:

package com.csdn.ingo.gof_Iterator;import java.util.ArrayList;import java.util.List;public class Window {public static void main(String[] args) {List products =new ArrayList();products.add("AAA");products.add("BBB");products.add("CCC");products.add("DDD");products.add("EEE");java.util.Iterator iterator = products.iterator();iterator.next();iterator.remove();while(iterator.hasNext()){System.out.println(iterator.next());}}}
特别提醒:remove()方法本身没有移动游标的位置。因此,在当前位置调用了remove()方法后,当前位置等于是“空”元素。如果不移动游标位置,再次调用remove()方法,将会抛出如下异常:


JDK的List与迭代器的实现说明,如下图:【以下内容自于其他博文,详情参考文章末尾】


 在JDK中,实际情况比上图要复杂很多,在中,List接口除了继承Collection接口的iterator()方法外,还增加了新的工厂方法listIterator(),专门用于创建ListIterator类型的迭代器。


List的子类LinkedList中实现了该方法,可用于创建具体的ListIterator子类ListItr的对象,如下所示:


  listIterator()方法用于返回具体迭代器ListItr类型的对象。在JDK源码中,AbstractList中的iterator()方法调用了listIterator()方法,如下:


客户端通过调用LinkedList类的iterator()方法,即可得到一个专门用于遍历Linkedlist的迭代器对象。

问题:

       既然有了iterator()方法,为什么还要提供一个listIterator()方法呢?这两个方法的功能不会存在重复吗?

解释:

       由于在Iterator接口中定义的方法太少,只有三个,通过这三个方法只能实现正向遍历,而有时候我们需要对一个聚合对象进行逆向遍历等操作,因此在JDKListIterator接口中声明了用于逆向遍历的hasPrevious()previous()等方法,如果客户端需要调用这两个方法来实现逆向遍历,就不能再使用iterator()方法来创建迭代器了,因为此时创建的迭代器对象是不具有这两个方法的。我们只能通过如下代码来创建ListIterator类型的迭代器对象:ListIterator i = c.listIterator();正因为如此,在JDKList接口中不得不增加对listIterator()方法的声明,该方法可以返回一个ListIterator类型的迭代器,ListIterator迭代器具有更加强大的功能。

反思:

应用场景:

  1. 需要(多种方式)遍历某个聚合对象,并且要求隐藏遍历细节。
  2. 对遍历对象需要进行,访问与控制分离。(可以理解为读写分离)
  3. 对客户端访问时提供统一的访问接口,聚合对象的结构差异不会影响客户端调用。

优点:

  1. 遍历的方法可定义多个,进而由不同的迭代器实现类完成即可。客户端保持统一调用方式。
  2. 对聚合对象的访问与控制进行了职责分离,简化了聚合对象的设计。
  3. 客户端面向接口编程,符合“开闭原则”。

缺点:

  1. 迭代器模式的实现过程需要大量的interface,class支撑。增删某个聚合类型都需要新增一组迭代器实现。其实现过程可能较为复杂。
  2. 完整的迭代功能较为复杂,在设计时,需要充分考虑未来的需求场景,错误的设计实现过程,很可能对性能,安全产生不利影响。

-------------------------------------------------------------------------------------------------------------------------------------

至此,被说了很多遍的设计模式---迭代器模式 结束


特别备注:上文中关于JDK源码的描述与List结构图,可能与当前JDK8版本有分歧。建议各位看官最好能够Debug跟踪学习。


参考资料:

图书:《大话设计模式》

其他博文:http://blog.csdn.NET/lovelion/article/details/7563445


0 0
原创粉丝点击