Iterator Pattern

Last Updated on September 24, 2023 by KnownSense

The Iterator Pattern also known as Cursor is a behavioral design pattern that provides a way to access elements of an aggregate object (such as a collection) sequentially without exposing the underlying representation of that object. It is used to traverse a container of elements, allowing clients to access its elements without needing to know the specific structure or implementation of the container.

One of the example of the Iterator Pattern can be found in many programming languages and libraries that provide built-in support for collections and iteration

Another example where the Iterator Pattern is widely used in Java is with database result sets and JDBC (Java Database Connectivity). JDBC provides a standard interface for connecting to and querying databases. When you execute a SQL query, you often get a result set, which is essentially a collection of rows from a database table. The Iterator Pattern is used to traverse and access these rows one by one.

public class IteratorPatternJDBCExample {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/mydatabase";
        String user = "username";
        String password = "password";

        try (Connection connection = DriverManager.getConnection(url, user, password);
             Statement statement = connection.createStatement();
             ResultSet resultSet = statement.executeQuery("SELECT * FROM employees")) {

            while (resultSet.next()) {
                int employeeId = resultSet.getInt("employee_id");
                String firstName = resultSet.getString("first_name");
                String lastName = resultSet.getString("last_name");
                double salary = resultSet.getDouble("salary");

                System.out.println("Employee ID: " + employeeId);
                System.out.println("Name: " + firstName + " " + lastName);
                System.out.println("Salary: " + salary);
                System.out.println("--------------------");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

Benefit

UML of Iterator Pattern

Key components of the Iterator Pattern:

  1. Iterator: This is an interface that defines methods like next(), hasNext(), and possibly remove(). It represents an abstraction for iterating over elements in a collection.
  2. Concrete Iterator: These are concrete implementations of the Iterator interface for specific types of collections. They keep track of the current position within the collection and provide the logic for moving to the next element.
  3. Aggregate: This is an interface that defines a method for creating an iterator. It represents the collection of elements that the iterator will traverse.
  4. Concrete Aggregate: These are concrete implementations of the Aggregate interface, representing different types of collections, such as arrays, lists, or trees. They provide an implementation for creating an iterator that is specific to their data structure.
Iterator Pattern

Implementation

Let’s create our own List Collection class that implement the iterator.

Step1: Create iterator interface with methods for iterating over elements.

interface Iterator<T> {
    boolean hasNext();

    T next();
}

Step2: Create ListIterator which is a concrete iterator for a list.

class ListIterator<T> implements Iterator<T> {
    private List<T> list;
    private int position;

    public ListIterator(List<T> list) {
        this.list = list;
        this.position = 0;
    }

    @Override
    public boolean hasNext() {
        return position < list.size();
    }

    @Override
    public T next() {
        if (!hasNext()) {
            throw new UnsupportedOperationException("No more elements to iterate");
        }
        T element = list.get(position);
        position++;
        return element;
    }
}

Step3: Create Aggregate which is the aggregate interface that defines a method for creating an iterator.

interface Aggregate<T> {
    Iterator<T> createIterator();
}

Step4: Create concrete aggregate List class representing a list of elements.

class List<T> implements Aggregate<T> {
    private List<T> elements = new ArrayList<>();

    public void add(T element) {
        elements.add(element);
    }

    @Override
    public Iterator<T> createIterator() {
        return new ListIterator<>(elements);
    }
}

Step5: In the main method, create a list, add elements to it, and use an iterator to traverse and print the elements.

public class IteratorPatternExample {
    public static void main(String[] args) {
        List<String> myList = new List<>();
        myList.add("Item 1");
        myList.add("Item 2");
        myList.add("Item 3");

        Iterator<String> iterator = myList.createIterator();

        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }

OUTPUT:
Item 1
Item 2
Item 3

Conclusion

The Iterator Pattern is a design pattern that provides a standardized way to access elements in a collection without exposing its internal structure. It encapsulates the iteration logic, simplifying client code and enabling the traversal of various types of collections. This pattern promotes code flexibility, separation of concerns, and improved maintainability in software design.

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to Top