Java模拟容器的迭代器(Iterator模式)
Iterator模式提供一系列的方法用于遍历某一类聚合对象的各个元素,在此,通过模拟容器的迭代器来学习Iterator模式。
首先,模拟实现JAVA中用得最多的ArrayList和LinkedList,当然这2类容器都是实现Collection接口的,为什么要实现Collection接口?最根本的原因肯定是多态。
1 /** 2 * 3 * @author LingJian 4 * 5 */ 6 public class ArrayList implements Collection { 7 private Object[] objects = new Object[10]; 8 private int index = 0; 9 10 public void add(Object o) { 11 if(index == objects.length) { 12 Object[] newObjects = new Object[objects.length * 2]; 13 System.arraycopy(objects, 0, newObjects, 0, objects.length); 14 objects = newObjects; 15 } 16 objects[index] = o; 17 index ++; 18 }; 19 20 public int size() { 21 return index; 22 }; 23 }
1 public class LinkedList implements Collection { 2 //头 3 private Node head = null; 4 //尾 5 private Node tail = null; 6 private int index = 0; 7 8 public void add(Object o) { 9 Node n = new Node(o,null); 10 if(head == null) { 11 head = n; 12 tail = n; 13 } 14 tail.setNext(n); 15 tail = n; 16 index ++; 17 } 18 19 public int size() { 20 return index; 21 } 22 }
1 public class Node { 2 private Object data; 3 private Node next; 4 public Object getData() { 5 return data; 6 } 7 public void setData(Object data) { 8 this.data = data; 9 } 10 public Node getNext() { 11 return next; 12 } 13 public void setNext(Node next) { 14 this.next = next; 15 } 16 public Node(Object data, Node next) { 17 super(); 18 this.data = data; 19 this.next = next; 20 } 21 }
1 /** 2 * 3 * @author LingJian 4 * 5 */ 6 public interface Collection { 7 public void add(Object o); 8 public int size(); 9 }
1 /** 2 * 3 * @author LingJian 4 * 5 */ 6 public class Test { 7 8 /** 9 * @param args 10 */ 11 public static void main(String[] args) { 12 Collection c = new LinkedList(); 13 for(int i=0; i<15; i++) { 14 c.add(new Cat(i)); 15 }; 16 System.out.println(c.size()); 17 18 19 } 20 21 }
1 /** 2 * 3 * @author LingJian 4 * 5 */ 6 public class Cat { 7 private int id; 8 9 public Cat(int id) { 10 super(); 11 this.id = id; 12 } 13 14 /** 15 * 方便打印查看 16 */ 17 @Override 18 public String toString() { 19 // TODO Auto-generated method stub 20 return "cat:" + id; 21 } 22 }
OK,如果不想用ArrayList,可以轻松切换LinkedList就能换一个容器,这就是多态给我们带来的好处。
现在,容器能容纳东西,那如果要取出来呢?
1 /** 2 * 3 * @author LingJian 4 * 5 */ 6 public class Test { 7 8 /** 9 * @param args 10 */ 11 public static void main(String[] args) { 12 Collection c = new ArrayList(); 13 for(int i=0; i<15; i++) { 14 c.add(new Cat(i)); 15 }; 16 System.out.println(c.size()); 17 18 ArrayList al = (ArrayList) c; 19 for(int i=0; i<al.size();i++) { 20 ..... 21 } 22 } 23 }
是的,这样写完全没有错,但是如果这时候发现容器换成了LinkedList,这段代码就需要全部替换了,因为LinkedList内部结构的实现是链表,遍历的方式不一样了,所以我们需要设计出一种可以不关注聚合对象内部元素结构的方法,不管是遍历什么容器,都能使用,无须更改方法。OK,Iterator模式就是为了解决这一一类问题而出现的,在这主要写LinkedList的Iterator。
1 /** 2 * 3 * @author LingJian 4 * 5 */ 6 public interface Iterator { 7 Object next(); 8 boolean hasNext(); 9 }
1 /** 2 * 3 * @author LingJian 4 * 5 */ 6 public class LinkedList implements Collection { 7 //头 8 private Node head = null; 9 //尾 10 private Node tail = null; 11 private int index = 0; 12 13 public void add(Object o) { 14 Node n = new Node(o,null); 15 if(head == null) { 16 head = n; 17 tail = n; 18 } 19 tail.setNext(n); 20 tail = n; 21 index ++; 22 } 23 24 public int size() { 25 return index; 26 } 27 28 @Override 29 public Iterator iterator() { 30 return new LinkedListIterator(); 31 } 32 33 public class LinkedListIterator implements Iterator { 34 35 @Override 36 public Object next() { 37 Object o = head.getData(); 38 head = head.getNext(); 39 return o; 40 } 41 42 @Override 43 public boolean hasNext() { 44 if(head == null) return false; 45 else return true; 46 } 47 48 } 49 }
1 /** 2 * 3 * @author LingJian 4 * 5 */ 6 public class Test { 7 8 /** 9 * @param args 10 */ 11 public static void main(String[] args) { 12 Collection c = new LinkedList(); 13 for(int i=0; i<15; i++) { 14 c.add(new Cat(i)); 15 }; 16 System.out.println(c.size()); 17 18 19 20 Iterator it = c.iterator(); 21 while(it.hasNext()) { 22 Object o = it.next(); 23 System.out.print(o + " "); 24 } 25 26 } 27 28 }
有了Iterator,遍历的聚合对象只要对外提供了自己符合要求的Iterator,这段遍历的方法便可重复使用,完全不需要关注元素的内部结构。
Iterator模式主要用于遍历,所以相对来说比较简单。