设计模式-迭代子模式(十六)

迭代子模式,又叫游标模式,该模式能顺序的访问一个聚集中的元素而不必暴露聚集的内部表象

  • 上类图:
设计模式-迭代子模式(十六)_第1张图片
迭代子模式.png

变化点:

  1. 在聚集系统的演化过程中,迭代逻辑没有变,但是需要将一种聚集换成另一种聚集。
  2. 聚集不会改变,但是聚集方式会改变

java中的集合分很多种,比如:ArrayList,LinkedList,TreeSet,HashSet等等这些就是我们说的不同聚集系统,不同的聚集有其不同的功能,如果我们不把通用的增删改查的操作抽象出来,那么每一种聚集(也就是每一个类)我们都得学习一下怎么用,就没有像现在只要学习一种其他的都一样,换一种聚集系统的时候,比如ArrayList换成LinkedList,而客户端的其他代码都不用修改这种效果了。

什么是主动迭代子和被动迭代子?
使用主动迭代子的客户端会显示的调用next等方法。

源码的 List,Set,Map 用了这个模式

  • 代码示例:
  1. 定义抽象的Iterator接口,定义迭代子的行为
package com.byedbl.iterator;

/**
 * Iterator Interface
 */
public interface Iterator {
    void first();

    void next();

    boolean isDone();

    void currentItem();
}
  1. 实现一个迭代子
package com.byedbl.iterator;
/**
 *  A vector iterator to print data reverse
 */
import java.util.*;

public class VectorIterator implements Iterator {
    private Vector data = new Vector();
    private int cursor = 0;

    public VectorIterator(Vector _data) {
        data = _data;
    }
    @Override
    public void first() {
        //cursor = 0;
        cursor = (data.size() - 1);
    }
    @Override
    public void next() {
        //cursor++;
        cursor--;
    }
    @Override
    public boolean isDone() {
        //return (cursor >= data.size());
        return (cursor < 0);
    }

    @Override
    public void currentItem() {
        if(isDone()) {
            System.out.println("Reach the end of the vector");
        } else {
            System.out.println("Number " + cursor + ": " + data.get(cursor));
        }
    }
}
  1. 定义聚集角色接口,给出创建迭代子的工厂方法
package com.byedbl.iterator;

/**
 *  The interface to create concrete iterator
 *  When create iterator, we can use Factory Method pattern
 */
public interface Aggregate  {
    Iterator createIterator();
}
  1. 实现一个聚集角色的接口
package com.byedbl.iterator;
/**
 * Data stored in a vector
 */
import java.io.*;
import java.util.*;

import static org.springframework.util.ClassUtils.*;

public class DataVector implements Aggregate {
    private Vector data = new Vector();

    public DataVector(String fileName) {
        try {
            String absolutePath = getDefaultClassLoader().getResource(fileName).getFile();
            BufferedReader f = new BufferedReader(new FileReader(absolutePath));
            String s = f.readLine();
            while (s != null) {
                if (s.trim().length() > 0) {
                    data.add(s);
                }
                s = f.readLine();
            }
            f.close();
        } catch (FileNotFoundException e) {
            System.out.println("Can not find such file !");
        } catch (IOException e) {
            System.out.println("I/O Error !");
            System.exit(0);
        }
    }

    @Override
    public Iterator createIterator() {
        return new VectorIterator(data);
    }

}
  1. 客户端用法
package com.byedbl.iterator; /**
 *
 */

public class Test  {
    public static void main(String[] args) {
        String fileName = "data.txt";
        Aggregate dataVector = new DataVector(fileName);
        Iterator iVector = dataVector.createIterator();
        for(iVector.first(); ! iVector.isDone(); iVector.next()) {
            iVector.currentItem();
        }
    }
}

好处:
  • 遍历的算法被封装在迭代子角色里面,因此迭代的算法可以独立于聚集角色变化
  • 客户端拿到的是一个迭代子对象,这样即使聚集对象发生变化也不用修改客户端遍历的代码

java中有个java.util.Iterator类使用了迭代子模式,在java.util.AbstractList.Itr内部类中实现了该接口,如果外界不是通过Iterator接口的remove方法删除的话会报ConcurrentModificationException异常

ListIterator接口继承自java.util.Iterator扩展了正向迭代和逆向迭代的功能,并提供了3个安全修改的方法,add(),remove(),set()
只有在调用了一次next或previous方法之后才能调用remove
,如果remove了之后还要调remove,必须先调用一次next或previous方法,set()方法也有类似的逻辑
java.util.AbstractList.ListItr 实现了该接口

你可能感兴趣的:(设计模式-迭代子模式(十六))