Design Patterns_Behavioral Patterns-《Iterator Patterns》
The notes are organized from the detailed explanation of Java design patterns by dark horse programmers, 23 Java design patterns (diagram + framework source code analysis + actual combat)
overview
definition
- Provides an object to sequentially access a range of data in an aggregate object without exposing the aggregate object's internal representation.
structure
Iterator Pattern mainly includes the following roles:
-
Abstract Aggregate (Aggregate) role: defines the interface for storing, adding, and removing aggregated elements, and creating iterator objects.
-
Concrete Aggregate role: implement an abstract aggregate class and return an instance of a concrete iterator.
-
Abstract iterator (Iterator) role: defines the interface for accessing and traversing aggregate elements, usually including hasNext(), next() and other methods.
-
Concrete iterator (Concrete iterator) role: implement the method defined in the abstract iterator interface, complete the traversal of the aggregated object, and record the current position of the traversal.
Case realization
[Example] Define a container object that can store student objects, and hand over the function of traversing the container to an iterator. The classes involved are as follows:
code show as below:
-
Abstract iterator role - iterator interface, declares hasNext(), next() methods
public interface StudentIterator { // 判断是否还有元素 boolean hasNext(); // 获取下一个元素 Student next(); }
-
Concrete iterator role class, overriding all abstract methods
public class StudentIteratorImpl implements StudentIterator { private List<Student> list; private int position = 0; // 记录遍历时的位置 public StudentIteratorImpl(List<Student> list) { this.list = list; } // 判断是否还有元素 @Override public boolean hasNext() { return position < list.size(); } // 获取下一个元素 @Override public Student next() { // 从集合中获取指定位置的元素 Student currentStudent = list.get(position); position++; return currentStudent; } }
-
Abstract container class (abstract aggregation role), including methods for adding elements, removing elements, and obtaining iterator objects
public interface StudentAggregate { // 添加学生功能 void addStudent(Student student); // 删除学生功能 void removeStudent(Student student); // 获取迭代器对象功能 StudentIterator getStudentIterator(); }
-
Concrete container class (concrete aggregate role), override all methods
public class StudentAggregateImpl implements StudentAggregate { private List<Student> list = new ArrayList<Student>(); // 学生列表 // 添加学生功能 @Override public void addStudent(Student student) { this.list.add(student); } // 删除学生功能 @Override public void removeStudent(Student student) { this.list.remove(student); } // 获取迭代器对象功能 @Override public StudentIterator getStudentIterator() { // 创建迭代器对象 return new StudentIteratorImpl(list); } }
-
student class
public class Student { private String name; private String number; // getter/setter... public Student(String name, String number) { this.name = name; this.number = number; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", number='" + number + '\'' + '}'; } }
-
test class
public class Client { public static void main(String[] args) { // 创建聚合对象 StudentAggregateImpl aggregate = new StudentAggregateImpl(); // 添加元素 aggregate.addStudent(new Student("张三", "001")); aggregate.addStudent(new Student("李四", "002")); aggregate.addStudent(new Student("王五", "003")); aggregate.addStudent(new Student("赵六", "004")); /* * 遍历聚合对象 */ // 1.获取迭代器对象 StudentIterator iterator = aggregate.getStudentIterator(); // 2.遍历 while (iterator.hasNext()) { // 3.获取元素 Student student = iterator.next(); System.out.println(student.toString()); } } }
output
Student{name='张三', number='001'} Student{name='李四', number='002'} Student{name='王五', number='003'} Student{name='赵六', number='004'}
Advantages and disadvantages
advantage
- It supports traversing an aggregate object in different ways, and multiple traversal methods can be defined on the same aggregate object. In the iterator mode, we only need to replace the original iterator with a different iterator to change the traversal algorithm. We can also define subclasses of iterators to support new traversal methods.
- Iterators simplify aggregation classes. Due to the introduction of iterators, there is no need to provide methods such as data traversal in the original aggregation objects, which can simplify the design of aggregation classes.
- In the iterator mode, due to the introduction of the abstraction layer, it is very convenient to add new aggregation classes and iterator classes without modifying the original code, which meets the requirements of the "opening and closing principle".
shortcoming
- The number of classes has been increased, which increases the complexity of the system to a certain extent.
scenes to be used
- When you need to provide multiple traversal methods for aggregate objects.
- When it is necessary to provide a unified interface for traversing different aggregation structures.
- When accessing the contents of an aggregate object without exposing its representation of internal details.
JDK source code analysis - collection class
The iterator mode is widely used in many collection classes of java, let's see how the iterator mode is used in the java source code.
List<String> list = new ArrayList<>();
Iterator<String> iterator = list.iterator(); // list.iterator()方法返回的肯定是Iterator接口的子实现类对象
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
After reading this code, is it familiar to you? It is basically similar to our code above. All single-column collections use iterators. Let's take ArrayList as an example:
- List: abstract aggregation class
- ArrayList: concrete aggregation class
- Iterator: abstract iterator
- list.iterator(): Returns
Iterator
a specific iterator object that implements the interface (in ArrayList, it is the internal class Itr)
Take a look at the code implementation of ArrayList specifically:
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
public Iterator<E> iterator() {
// 返回的肯定是Iterator的子实现类对象
return new Itr();
}
||
\/
// 内部类Itr 实现了Iterator接口 并且重写了 hasNext() 和 next() 方法。
private class Itr implements Iterator<E> {
int cursor; // 下一个要返回元素的索引
int lastRet = -1; // 上一个返回元素的索引
int expectedModCount = modCount;
Itr() {
}
// 判断是否还有元素
public boolean hasNext() {
return cursor != size;
}
// 获取下一个元素
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
...
}
This part of the code is relatively simple, roughly, iterator
an instantiated Iterator
object is returned in the method, Itr is an inner class, which implements Iterator
the interface and rewrites the abstract method in it.
Notice:
When we are developing in java, if we want to use the iterator mode, we only need to let our self-defined container class implement
java.util.Iterable
and implement the iterator() method in it to return anjava.util.Iterator
implementation class of .