Head First design pattern: iterator pattern

text

1, Definition

The iterator pattern provides a way to sequentially access the elements of an aggregate object without exposing its internal representation.

main points:

  • The iterator pattern places the responsibility for swimming between elements on the iterator, not the aggregate object. This simplifies the interface and implementation of aggregation, and makes each responsibility its own.

2, Implementation steps

1. Create iterator interface

/**
 * Iterator Interface 
 */
public interface Iterator {

    /**
     * Is there a next element
     */
    public boolean hasNext();
    
    /**
     * Get next element
     */
    public Object next();
}

2. Create a concrete iterator and implement the iterator interface

The specific iterator is responsible for traversing the elements and managing the current traversal location.

/**
 * Concrete iterator
 */
public class ConcreteIterator implements Iterator {
    
    /**
     * Collection (array) to traverse
     */
    public String[] items;
    /**
     * Current traversal position
     */
    int position = 0;
    
    public ConcreteIterator(String[] items) {
        this.items = items;
    }

    @Override
    public boolean hasNext() {
        if (position < items.length) {
            return true;
        }
        return false;
    }

    @Override
    public Object next() {
        if (!this.hasNext()) {
            return null;
        }
        String item = items[position];
        position = position + 1;
        return item;
    }
}

3. Create an aggregation interface and define the method that returns the iterator

/**
 * Aggregate interface
 */
public interface Aggregate {

    /**
     * Create iterator
     */
    public Iterator createIterator();
}

4. Create concrete aggregates and implement methods that return iterators

A collection held in a specific aggregation. The collection here refers to a group of objects, which can be stored in lists, arrays, hash tables, etc.

/**
 * Specific aggregation
 */
public class ConcreteAggregate implements Aggregate {
    
    /**
     * Hold sets (such as lists, arrays, hash tables, etc.)
     */
    public String[] items = new String[] {"item1", "item2", "item3"};

    @Override
    public Iterator createIterator() {
        return new ConcreteIterator(items);
    }
}

5. Traversal using iterators

public class Test {
    
    public static void main(String[] args) {
        // Aggregate object
        Aggregate aggregate = new ConcreteAggregate();
        // iterator 
        Iterator iterator = aggregate.createIterator();
        // ergodic
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

3, Take a chestnut

1. Background

Object village restaurant and object village pancake house have been merged. Now we can enjoy the delicious pancake breakfast and lunch in the same place.

Suppose you are hired by their new company and plan to create a Java version of the waitress. The specification of this Java version of the waitress is: it can respond to the needs of customers and print customized menus without asking the chef.

Now, there's a little trouble: the pancake house menu uses ArrayList to record menu items, while the restaurant uses array to record menu items. Neither wants to change their implementation. After all, too much code depends on them.

The good news is that pancake houses and restaurants have agreed to implement a unified menu item MenuItem.

2. Realize

Pass the traversal of the collection to the iterator, so that you don't care whether the menu uses ArrayList or array to record menu items.

(1) Create menu item

/**
 * menu item
 */
public class MenuItem {

    String name;
    double price;
    
    public MenuItem(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }
}

(2) Create iterator interface

/**
 * Iterator Interface 
 */
public interface Iterator {

    /**
     * Is there a next element
     */
    public boolean hasNext();
    
    /**
     * Get next element
     */
    public Object next();
}

(3) Create a concrete menu iterator

/**
 * Pancake house menu iterator
 */
public class PancakeHouseMenuIterator implements Iterator {
    
    /**
     * Menu items in list form
     */
    public ArrayList<MenuItem> menuItems;
    int position = 0;
    
    public PancakeHouseMenuIterator(ArrayList<MenuItem> items) {
        this.menuItems = items;
    }

    @Override
    public boolean hasNext() {
        if (position < menuItems.size()) {
            return true;
        }
        return false;
    }

    @Override
    public Object next() {
        if (!this.hasNext()) {
            return null;
        }
        MenuItem item = menuItems.get(position);
        position = position + 1;
        return item;
    }
}
/**
 * Restaurant menu iterator
 */
public class DinerMenuIterator implements Iterator {
    
    /**
     * Menu items in array form
     */
    public MenuItem[] menuItems;
    int position = 0;
    
    public DinerMenuIterator(MenuItem[] items) {
        this.menuItems = items;
    }

    @Override
    public boolean hasNext() {
        if (position < menuItems.length) {
            return true;
        }
        return false;
    }

    @Override
    public Object next() {
        if (!this.hasNext()) {
            return null;
        }
        MenuItem item = menuItems[position];
        position = position + 1;
        return item;
    }
}

(4) Create menu interface

/**
 * Menu interface
 */
public interface Menu {

    /**
     * Create iterator
     */
    public Iterator createIterator();
}

(5) Create specific menus

/**
 * Pancake house menu
 */
public class PancakeHouseMenu implements Menu {
    
    public ArrayList<MenuItem> menuItems;
    
    public PancakeHouseMenu() {
        menuItems = new ArrayList<MenuItem>();
        menuItems.add(new MenuItem("Regular Pancake Breakfast", 2.99));
        menuItems.add(new MenuItem("Blueberry Pancakes", 3.49));
        menuItems.add(new MenuItem("Waffles", 3.59));
    }

    @Override
    public Iterator createIterator() {
        return new PancakeHouseMenuIterator(menuItems);
    }
}
/**
 * Restaurant menu
 */
public class DinerMenu implements Menu {
    
    public MenuItem[] menuItems;
    
    public DinerMenu() {
        menuItems = new MenuItem[3];
        menuItems[0] = new MenuItem("BLT", 2.99);
        menuItems[1] = new MenuItem("Soup of the day", 3.29);
        menuItems[2] = new MenuItem("Hotdog", 3.05);
    }

    @Override
    public Iterator createIterator() {
        return new DinerMenuIterator(menuItems);
    }
}

(6) Create waitress

/**
 * waitress
 */
public class Waitress {
    
    Menu pancakeHouseMenu;
    Menu dinerMenu;
    
    public Waitress(Menu pancakeHouseMenu, Menu dinerMenu) {
        this.pancakeHouseMenu = pancakeHouseMenu;
        this.dinerMenu = dinerMenu;
    }
    
    public void printMenu() {
        // Get menu iterator
        Iterator pancakeIterator = pancakeHouseMenu.createIterator();
        Iterator dinerIterator = dinerMenu.createIterator();
        // Print menu using iterator
        System.out.println("----MENU----\n");
        System.out.println("BREAKFASE:");
        printMenu(pancakeIterator);
        System.out.println("\nLUNCH:");
        printMenu(dinerIterator);
    }
    
    private void printMenu(Iterator iterator) {
        while (iterator.hasNext()) {
            MenuItem menuItem = (MenuItem)iterator.next();
            System.out.println(menuItem.getName() + ", " + menuItem.getPrice());
        }
    }
}

(7) Using the waitress print menu

public class Test {
    
    public static void main(String[] args) {
        // menu
        Menu pancakeHouseMenu = new PancakeHouseMenu();
        Menu dinerMenu = new DinerMenu();
        // waitress
        Waitress waitress = new Waitress(pancakeHouseMenu, dinerMenu);
        // Print menu
        waitress.printMenu();
    }
}

Tags: Design Pattern

Posted by Maharg105 on Thu, 19 May 2022 05:41:33 +0300