Before I talk about this design pattern, let me talk about how a container can be implemented. We all know that ArrayList arrays can add elements to it, so why don't we worry about overflowing an array? Because in this container, it can expand automatically, so how to achieve it?
First of all, we all know that a container must have a way to add elements to it:
public void add(Object o){ if(count == object.length) { Object[] newObj = new Object[2 * object.length]; System.arraycopy(object, 0, newObj, 0, object.length); } object[count] = o; count++; }
Here count is the number of elements, that is, if this if determines if the current set element is full, then expand the array, then COPY the original array into the new array, and assign a value.
Get the number of elements in an array:
public int length(){ return count; }
Suppose we create a linked list container:
public class myList { private Node head = null; private Node tail = null; private int size = 0; public void add(Object o) { Node n = new Node(o, null); if(head == null){ head = n; tail = n; } tail.setN(n); tail = n; size++; } public int length() { return size; } }
Here, the container is built on the same principle as an array. First, a new node is created, and the data is put into the data field of the new node. Then, the pointer field is set to be empty. Then, it is placed at the end of the list, and the tail pointer is pointed to the node.
When I use these two containers next, let me say that I am using one of them:
public class Test { public static void main(String[] args) { MyArrayList arr = new MyArrayList(); for(int i = 0; i < 3; ++i){ arr.add(i); } } }
Suddenly, I don't want to use arrays. I want to use linked list containers. So suppose there's a lot of code behind me, do I have to change all the code behind me? So is there a solution? The answer must be yes, so we need to define an interface so that all the containers can implement the methods in it. Then by using polymorphic calls, we can achieve the following code without moving.
public class Test { public static void main(String[] args) { Collection arr = new MyArrayList(); for(int i = 0; i < 3; ++i){ arr.add(1); } } }
According to this principle, when we want to traverse a container, if we are traversing an array container, and then I don't want to use an array container, I want to use a linked list container, then we all know that traversing an array is definitely different from traversing a linked list. Are we going to change the code foolishly at this time?
In fact, we need to use iterators at this time. We separate the function of traversing containers and add interfaces to realize this function, which weakens the coupling between classes and enhances the reusability, maintainability and flexibility of code.
Define interfaces:
/* * Define two methods for the container to implement it, determine whether the next one has a value, and obtain the value of the next element. */ public interface Iterator { Object next(); boolean hasNext(); }
One is to get the next element, the other is to determine whether there are elements after it, the data type returned is to boolean, if true, or false, and then let the container implement these two functions.
Implementation code:
private class arrayListIterator implements Iterator{ int currentIndex = 0; public boolean hasNext() { if(currentIndex >= count) return false; else return true; } public Object next(){ Object o = object[currentIndex]; currentIndex++; return o; } }
Then we will be unified in traversing:
public class Test { public static void main(String[] args) { Collection arr = new MyArrayList(); for(int i = 0; i < 3; ++i){ arr.add(i); } Iterator i = arr.iterator(); while(i.hasNext()){ System.out.println(i.next()); } } }
So at this point, we want to use linked list containers:
public class Test { public static void main(String[] args) { Collection arr = new myList(); for(int i = 0; i < 3; ++i){ arr.add(i); } arr.add(2); Iterator i = arr.iterator(); while(i.hasNext()){ System.out.println(i.next()); } } }
At this time, there is no need to change the code behind. In our practical application, this situation makes it very common, so the use of iterators, as mentioned earlier, weakens the coupling between classes, and enhances the reusability, maintainability and flexibility of code.