迭代器模式小试

迭代器模式小试

迭代器是行为型设计模式的一种,是一种非常简单的设计模式。

转载请注明出处 http://www.cnblogs.com/zrtqsk/p/3716173.html,谢谢!

一、介绍

  先来看一下《研磨设计模式》的定义——提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。

  迭代器模式的本质是——控制访问聚合对象中的元素

  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 }

结果与之前没有什么不同。