“This is the 28th day of my participation in the August Genwen Challenge.More challenges in August”

What is the iterator pattern?

The Iterator Pattern, also known as Cursor Pattern, provides a way to access the elements of a collection/container sequentially without exposing the internal representation of the collection. The iterator pattern provides consistent traversal behavior for different containers, regardless of the structure of the container’s content elements. It is a behavioral pattern.

The essence of the iterator pattern is to extract the collection object iteration behavior into the iterator, providing a consistent access interface.

The application scenario of iterator pattern

The iterator mode is also widely used in our daily life. For example, the conveyor belt in the logistics system is packed into boxes one by one and has a unified TWO-DIMENSIONAL code. In this way, we don’t need to care about what is inside the box, we just need to check the destination of the delivery one by one when distributing. Another example is that when we take transport, we swipe our card or face to get into the station, and we do not need to care about the personalized information of male or female, disabled or normal people.

An Aggregate of objects is called an Aggregate, which is a container that can contain a group of objects. Different collection of its internal elements of the aggregation structure may be different, but the iterator pattern blocked internal elements to get details, to provide external access behavior consistent with the elements, decoupling the coupling between the element iteration and the collection objects, and by providing different iterator that can provide with a collection of objects with different order element access behavior, expanded the collection object element iteration function, In line with the open and close principle.

The iterator pattern applies to the following scenarios:

  1. Access the contents of a collection object without exposing its internal representation.
  2. Provides a unified access interface for traversing different collection structures.

Roles involved in the iterator pattern

Let’s start with the generic UML class diagram for the iterator pattern:

From the UML class diagram, we can see that the iterator pattern consists of three main roles:

  1. Abstract iterators: Abstract iterators are responsible for defining interfaces that access and iterate over elements.
  2. Concrete iterators: Provide concrete element traversal behavior.
  3. Aggregate: Responsible for defining interfaces that provide concrete iterators.
  4. Concrete Aggregates: Create concrete iterators.

4. Handwritten custom iterators

In general, iterators are pretty simple. Let’s still take the course as an example. Let’s create a set of courses by ourselves, and each element in the set is the course object. Then we write an iterator by ourselves to read the information of each course object.

First create a set element Course class:

public class Course {
    private String name;

    public Course(String name) {
        this.name = name;
    }

    public String getName(a) {
        returnname; }}Copy the code

Then create the custom Iterator Iterator interface:

public interface Iterator<E> {

    E next(a);

    boolean hasNext(a);
}
Copy the code

Then create a custom CourseAggregate interface:

public interface CourseAggregate {

    void add(Course course);

    void remove(Course course);

    Iterator<Course> iterator(a);
}
Copy the code

Then, implement the iterator interface and the collection interface respectively and create the IteratorImpl implementation class:

public class IteratorImpl<E> implements Iterator<E> {

    private List<E> list;
    private int cursor;
    private E element;

    public IteratorImpl(List<E> list) {
        this.list = list;
    }

    @Override
    public E next(a) {
        System.out.print("Current location" + cursor + ":");
        this.element = list.get(cursor);
        cursor++;
        return this.element;
    }

    @Override
    public boolean hasNext(a) {
        if (cursor > list.size() - 1) {
            return false;
        }
        return true; }}Copy the code

CourseAggregateImpl Implementation class:

public class CourseAggregateImpl implements CourseAggregate {

    private List courseList;

    public CourseAggregateImpl(a) {
        this.courseList = new ArrayList();
    }

    @Override
    public void add(Course course) {
        courseList.add(course);
    }

    @Override
    public void remove(Course course) {
        courseList.remove(course);
    }

    @Override
    public Iterator<Course> iterator(a) {
        return newIteratorImpl<>(courseList); }}Copy the code

Then, write the client code:

public class Test {

    public static void main(String[] args) {
        Course java = new Course("Java architecture");
        Course javaBase = new Course("Java foundation");
        Course design = new Course("Java Design Patterns");
        Course ai = new Course("Artificial intelligence");

        CourseAggregate courseAggregate = new CourseAggregateImpl();
        courseAggregate.add(java);
        courseAggregate.add(javaBase);
        courseAggregate.add(design);
        courseAggregate.add(ai);

        System.out.println("---------- Course list ------------");
        printCourses(courseAggregate);
    }

    private static void printCourses(CourseAggregate courseAggregate) {
        Iterator<Course> iterator = courseAggregate.iterator();
        while (iterator.hasNext()) {
            Course course = iterator.next();
            System.out.println("" " + course.getName() + "" "); }}}Copy the code

The running results are as follows:

Five, iterator mode in the source code

Iterator: Iterator: Iterator: Iterator

public interface Iterator<E> {
   
    boolean hasNext(a);

    E next(a);

    default void remove(a) {
        throw new UnsupportedOperationException("remove");
    }

    default void forEachRemaining(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        while(hasNext()) action.accept(next()); }}Copy the code

From the code above, we can see that the two main methods define hasNext() and next() methods, exactly as we wrote ourselves.

Iterator: Iterator: Iterator: Iterator: Iterator: Iterator: Iterator: Iterator: Iterator: Iterator: Iterator: Iterator: Iterator: Iterator: Iterator: Iterator: Iterator: Iterator: Iterator: Iterator: Iterator: Iterator: Iterator

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess.Cloneable.java.io.Serializable
{...private class Itr implements Iterator<E> {
      int cursor; // index of next element to return
      int lastRet = -1; // index of last element returned; -1 if no such
      int expectedModCount = modCount;

      public boolean hasNext(a) {
        returncursor ! = size; }@SuppressWarnings("unchecked")
      public E next(a) {
        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]; }}... }Copy the code

Advantages and disadvantages of the iterator pattern

Advantages:

  1. Polymorphic iteration: Provides a consistent traversal interface for different aggregate structures, i.e. an iterative interface can access different collection objects.
  2. Simplified collection object interface: The iterator pattern abstracts the element iteration interface that the collection object itself should provide into the iterator, leaving the collection object unconcerned about the specific iteration behavior.
  3. Element iteration capability diversification: Each collection object can provide one or more different iterators, allowing the same element aggregation structure to have different iteration behavior.
  4. Decoupled iteration and collection: The iterator pattern encapsulates the specific iterative algorithm, and changes to the iterative algorithm do not affect the architecture of the collection object.

Disadvantages:

For simple traversal (like arrays or ordered lists), iterator traversal is cumbersome. In daily development, we almost never write iterators ourselves. Unless we need to customize an iterator that corresponds to our own data structure, the API provided by the open source framework is perfectly adequate.

7. Friendship links

Design Patterns – Factory Patterns learning tour

Design Patterns – a learning tour of singleton patterns

Design Patterns – A learning journey of prototyping patterns

Design Patterns – Builder patterns learning tour

Design Patterns – Agent patterns learning tour

Design Patterns – A learning tour of facade patterns

Design Patterns – A learning tour of decorator patterns

Design Patterns – Enjoy yuan patterns learning journey

Design Patterns – A learning journey of composite patterns

Design Patterns – Adapter patterns learning journey

Design Patterns – Bridge patterns learning journey

Design Patterns – Delegation patterns learning journey

Design Patterns – a template method pattern learning journey

Design Patterns – A learning journey of Strategic patterns

Design Patterns – A learning journey of chain of Responsibility patterns

Welcome to follow the wechat public account (MarkZoe) to learn from and communicate with each other.