一、介绍
先来看一下《研磨设计模式》的定义——提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。
迭代器模式的本质是——控制访问聚合对象中的元素
Java中有的聚合对象主要是Collection类、Map类的各子类对象。同样的,数组也算一种聚合对象。迭代器模式就是希望从外部用同一种方式去访问不同的聚合对象。这个怎么做呢?
说白了,就是创建一个迭代类,持有聚合对象,并且提供迭代这个聚合对象的方法。这个迭代类怎么得到呢?让原本的聚合对象增加一个方法,可以用来返回一个迭代对象,返回时,将自身传递给这个迭代对象。我们得到了这个迭代对象,就可以轻松的在外部访问这个聚合对象了。
二、我的实现
1、假设我们本身有一个包含简单功能的聚合类MyList,如下:
复制代码
1 public class MyList<T> {
2
3 private Object[] elements;
4 //容量
5 private int capacity = 10;
6 //当前大小
7 private int size = 0;
8
9 //指定容量的构造方法
10 public MyList(int capacity){
11 this.capacity = capacity;
12 elements = new Object[10];
13 }
14
15 //默认构造方法
16 public MyList(){
17 this(10);
18 }
19
20 public int size(){
21 return size;
22 }
23
24 public T get(int i){
25 if(i > capacity){
26 System.out.println("List数组越界");
27 return null;
28 }else {
29 return (T) elements[i];
30 }
31 }
32
33 public void add(T obj){
34 if(size >= capacity){
35 //扩容
36 }else {
37 elements[size ++] = obj;
38 }
39 }
40 }
复制代码
2、测试一下:
复制代码
1 public class Test {
2
3 public static void main(String[] args)
4 {
5 MyList<Apple> list = new MyList<Apple>();
6 list.add(new Apple("a"));
7 list.add(new Apple("b"));
8 System.out.println(list.get(0));
9 System.out.println(list.get(1));
10 System.out.println(list.get(3));
11 }
12 }
13
14 class Apple{
15 private String name;
16
17 public Apple(String name){
18 this.name = name;
19 }
20
21 public String toString(){
22 return "Apple:" + name;
23 }
24
25 }
复制代码
3、结果如下:
Apple:a
Apple:b
List数组越界
null
可见功能正常。
4、我们需要从外部访问这个聚合对象,该怎么做呢?
如前面说的,写一个简单的访问数据的接口,包含简单的迭代聚合对象的功能如下:
1 public interface Iterator<T> {
2
3 public T next();
4
5 public boolean hasNext();
6 }
5、简单的实现类;
复制代码
1 public class IteratorImpl<T> implements Iterator<T> {
2
3 private int index = 0;
4 MyList list = null;
5 public IteratorImpl(MyList list){
6 this.list = list;
7 }
8
9 @Override
10 public T next()
11 {
12 return (T) list.get(index++);
13 }
14
15 @Override
16 public boolean hasNext()
17 {
18 boolean flag = false;
19 if(list.get(index) != null){
20 flag = true;
21 }
22 return flag;
23 }
24 }
复制代码
6、构建一个简单的抽象类AbstractList,而实际上List的大部分方法都可以放到这个抽象类来,这里为了演示方便,如下:
1 public abstract class AbstractList {
2
3 public abstract Iterator iterator();
4 }
7、刚才的MyList继承这个抽象类,其实现方法如下:
1 @Override
2 public Iterator iterator()
3 {
4 return new IteratorImpl(this);
5 }
非常简单!
8、下面我们就是测试,测试类比之前改变一点点,如下;
复制代码
1 public class Test {
2
3 public static void main(String[] args)
4 {
5 MyList<Apple> list = new MyList<Apple>();
6 list.add(new Apple("a"));
7 list.add(new Apple("b"));
8 // System.out.println(list.get(0));
9 // System.out.println(list.get(1));
10 // System.out.println(list.get(3));
11 Iterator it = list.iterator();
12 while(it.hasNext()){
13 System.out.println(it.next());
14 }
15 }
16 }
复制代码
9,结果如下:
Apple:a
Apple:b
提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。这就是迭代器模式。
三、Java的迭代器
通常而言,我们遍历一个聚合对象除了使用Iterator外,还有一种更简便的方法,那就是用简易的for循环——for(Type t : Collection)。但是当我们用这个方式去访问上文我自定义的聚合对象MyList的时候,发现编译错误。错误提示说,因为我们没有实现java.lang.Iterable接口。 这个接口位于java.lang包下,意味着我们不用额外导包了。我们来看一下这个接口的源代码:
复制代码
package java.lang;
import java.util.Iterator;
public interface Iterable<T> {
Iterator<T> iterator();
}
复制代码
可见,这个接口只有一个方法,用来返回一个java.util.Iterator接口对象。相当于我们刚才的抽象类。
Java的迭代器实现主要就是围绕着这两个接口,我们来看一下java.util.Iterator的源代码
复制代码
package java.util;
public interface Iterator<E> {
boolean hasNext();
E next();
void remove();
}
复制代码
可以看到,这个接口是非常简单的。跟上面我自定义的Iterator相比,只是多了一个void remove()方法。
下面我们将上面的例子改为Java的迭代器实现。通常而言,由于一个Iterator的实现类是对应一个聚合对象的。为了提高内聚性,我们应该将Iterator实现类作为聚合对象的内部类。而JDK也是这么做的。如下:
复制代码
1 import java.util.Iterator;
2
3 //实现Iterable接口
4 public class MyList<T> implements Iterable<T>{
5
6 private Object[] elements;
7 // 容量
8 private int capacity = 10;
9 // 当前大小
10 private int size = 0;
11
12 // 指定容量的构造方法
13 public MyList(int capacity)
14 {
15 this.capacity = capacity;
16 elements = new Object[10];
17 }
18
19 // 默认构造方法
20 public MyList()
21 {
22 this(10);
23 }
24
25 public int size()
26 {
27 return size;
28 }
29
30 public T get(int i)
31 {
32 if (i > capacity)
33 {
34 System.out.println("List数组越界");
35 return null;
36 }
37 else
38 {
39 return (T) elements[i];
40 }
41 }
42
43 public void add(T obj)
44 {
45 if (size >= capacity)
46 {
47 // 扩容
48 }
49 else
50 {
51 elements[size++] = obj;
52 }
53 }
54
55 //返回java.util.Iterator对象
56 @Override
57 public Iterator iterator()
58 {
59 return new IteratorImpl(this);
60 }
61
62 //内部类
63 class IteratorImpl<T> implements Iterator<T> {
64
65 private int index = 0;
66 MyList list = null;
67
68 public IteratorImpl(MyList list)
69 {
70 this.list = list;
71 }
72
73 @Override
74 public T next()
75 {
76 return (T) list.get(index++);
77 }
78
79 @Override
80 public boolean hasNext()
81 {
82 boolean flag = false;
83 if (list.get(index) != null)
84 {
85 flag = true;
86 }
87 return flag;
88 }
89
90 @Override
91 public void remove()
92 {
93
94 }
95 }
96 }
复制代码
同时,我们还可以使用简易for循环迭代这个聚合对象,如下:
复制代码
1 public class Test {
2
3 public static void main(String[] args)
4 {
5 MyList<Apple> list = new MyList<Apple>();
6 list.add(new Apple("a"));
7 list.add(new Apple("b"));
8 // System.out.println(list.get(0));
9 // System.out.println(list.get(1));
10 // System.out.println(list.get(3));
11 Iterator it = list.iterator();
12 for(Apple a : list ){
13 System.out.println(a);
14 }
15 }
16 }
复制代码
结果与之前没有什么不同。