Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Applied Java™ Patterns - Stephen Stelting, Olav Maassen.pdf
Скачиваний:
202
Добавлен:
24.05.2014
Размер:
2.84 Mб
Скачать

Additionally, Iterators allow clients to keep multiple navigation points to the same collection. You can think of an Iterator as a cursor or pointer into the collection; with each call to the Aggregate's factory method, you can get another pointer into the collection.

A drawback of iterators is that they give the illusion of order to unordered structures. For example, a set does not support ordering, and its Iterator would likely provide the elements in an arbitrary sequence that could change over time. If you don’t realize this, you could write code that assumed consistency in the underlying structure, which would result in problems later on.

Pattern Variants

The Iterator pattern has a number of implementation options.

A ConcreteIterator may be internal or external. External Iterators provide specific methods to the clients to navigate within the collection, while internal Iterators cycle through the elements, performing some action requested by the client. The external iterator is the more flexible option, but requires more coding on the client to use the iterator.

ConcreteIterators can be dynamic or static. A dynamic ConcreteIterator directly references its underlying collection for elements, so is always guaranteed to reflect its state. A static ConcreteIterator, on the other hand, creates a snapshot of the collection when it is created, and refers to the copy during client use.

Null iterators can be defined to make traversal of complex structures, such as trees, more straightforward. Using an iterator that represents an “end node,” it is possible to write simple recursive code to visit all the nodes in the tree.

Iterators can support a variety of different ways to move through a collection. This is particularly useful in complex structures, such as the Composite pattern, where there might be a rationale to move through the elements in a variety of different ways.

From a structural perspective, a ConcreteIterator can be defined as an inner class of the ConcreteAggregate, or it can be defined in a separate class. The ConcreteIterator can hold the code to move through the collection, or it might only represent the position within the collection.

Related Patterns

Related patterns include the following:

Factory Method (page 21) – Collection classes often define a factory method to produce the Iterator.

Visitor (page 121) – When the Visitor pattern is used on a group of objects, an Iterator is frequently used to cycle through the elements.

Value List Handler [CJ2EEP] – The Value List Handler is based on the Iterator pattern in that it allows the client to step through a collection.

Example

Note:

For a full working example of this code example, with additional supporting classes and/or a RunPattern class, see “ Iterator ” on page 389 of the “ Full Code Examples ” appendix.

This example uses the Java Collections Framework to provide iterating behavior for a pair of business aggregates. The java.util.Iterator interface defines methods for the basic navigation methods required— hasNext and next. Note that the Iterator interface requires one-time-only traversal, since the only way to return to the beginning is to get another Iterator from the collection.

The Iterating interface defines a single method, getIterator. This interface is used to identify any class in the PIM that is capable of producing an Iterator for collection traversal.

54

Example 2.19 Iterating.java

1.import java.util.Iterator;

2.import java.io.Serializable;

3.public interface Iterating extends Serializable{

4.public Iterator getIterator();

5.}

The ToDoList and ToDoListCollection interfaces, which extend the Iterating interface, define the two collections in the example. ToDoList defines a sequential list of tasks or items, while ToDoListCollection represents a collection of ToDoLists stored in the PIM.

Example 2.20 ToDoList.java

1.public interface ToDoList extends Iterating{

2.public void add(String item);

3.public void add(String item, int position);

4.public void remove(String item);

5.public int getNumberOfItems();

6.public String getListName();

7.public void setListName(String newListName);

8.}

Example 2.21 ToDoListCollection.java

1.public interface ToDoListCollection extends Iterating{

2.public void add(ToDoList list);

3.public void remove(ToDoList list);

4.public int getNumberOfItems();

5.}

The classes ToDoListImpl and ToDoListCollectionImpl implement the previous interfaces. ToDoListImpl uses an ArrayList to hold its elements, which provides absolute ordering and allows duplicate entries. ToDoListCollectionImpl uses a HashTable, which does not support ordering and stores its entries as key-value pairs. Although the collections behave very differently, both can provide Iterators for their stored elements.

Example 2.22 ToDoListCollectionImpl.java

1.import java.util.Iterator;

2.import java.util.HashMap;

3.public class ToDoListCollectionImpl implements ToDoListCollection{

4.private HashMap lists = new HashMap();

5.

6.public void add(ToDoList list){

7.if (!lists.containsKey(list.getListName())){

8. lists.put(list.getListName(), list);

9.}

10.}

11.public void remove(ToDoList list){

12.if (lists.containsKey(list.getListName())){

13. lists.remove(list.getListName());

14.}

15.}

16.public int getNumberOfItems(){ return lists.size(); }

17.public Iterator getIterator(){ return lists.values().iterator(); }

18.public String toString(){ return getClass().toString(); }

19.}

Example 2.23 ToDoListImpl.java

1.import java.util.Iterator;

2.import java.util.ArrayList;

3.public class ToDoListImpl implements ToDoList{

4.private String listName;

5.private ArrayList items = new ArrayList();

7.public void add(String item){

8.if (!items.contains(item)){

9. items.add(item);

10.}

11.}

12.public void add(String item, int position){

13.if (!items.contains(item)){

14. items.add(position, item);

15.}

16.}

55

17.public void remove(String item){

18.if (items.contains(item)){

19. items.remove(items.indexOf(item));

20.}

21.}

23.public int getNumberOfItems(){ return items.size(); }

24.public Iterator getIterator(){ return items.iterator(); }

25.public String getListName(){ return listName; }

26.public void setListName(String newListName){ listName = newListName; }

28.public String toString(){ return listName; }

29.}

Both classes can provide an Iterator, so it's straightforward to write code to move through their elements. ListPrinter shows how the Iterators could be used to print the contents of collections out in their String form. The class has three methods: printToDoList, printToDoListCollection and printIteratingElement. In all three methods, the iteration process is based around a very simple while loop.

Example 2.24 ListPrinter.java

1.import java.util.Iterator;

2.import java.io.PrintStream;

3.public class ListPrinter{

4.public static void printToDoList(ToDoList list, PrintStream output){

5.Iterator elements = list.getIterator();

6.output.println(" List - " + list + ":");

7.while (elements.hasNext()){

8. output.println("\t" + elements.next());

9.}

10.}

12.public static void printToDoListCollection(ToDoListCollection lotsOfLists,

PrintStream output){

13.Iterator elements = lotsOfLists.getIterator();

14.output.println("\"To Do\" List Collection:");

15.while (elements.hasNext()){

16. printToDoList((ToDoList)elements.next(), output);

17.}

18.}

20.public static void printIteratingElement(Iterating element, PrintStream output){

21.output.println("Printing the element " + element);

22.Iterator elements = element.getIterator();

23.while (elements.hasNext()){

24.

Object currentElement = elements.next();

25.

if (currentElement instanceof Iterating){

26.

printIteratingElement((Iterating)currentElement, output);

27.

output.println();

28.

}

29.

else{

30.

output.println(currentElement);

31.

}

32.}

33.}

34.}

The method printIteratingElement best demonstrates the power of combining the Iterator pattern with polymorphism. Here, any class that implements Iterating can be printed in String form. The method makes no assumptions about the underlying collection structure except that it can produce an Iterator.

56