venerdì 28 novembre 2008

Iterator Design Pattern

ITERATOR DESIGN PATTERN:
Obiettivo: fornire un meccanismo che permetta di 'esplorare' una lista di collection o oggetti aggregati senza conoscerne la rappresentazione interna.

Nel nostro esempio useremo il pattern Iterator per stampare sullo standard output una lista di stringhe.

package designPatterns.iterator;
interface StringListIterator {
    public void first();
    public void next();
    public boolean isDone();
    public String currentString();
}

class StringList {
    private String[] strings;
    private int currIndex;
    private int size;
    public StringList(int size) {
        strings = new String[size];
        currIndex = 0;
        this.size = size;
    }
    public int count() {
        return currIndex;
    }
    public void append(String titleIn) {
        if (currIndex >= size) {
            String[] tempArray = new String[size];
            for (int i = 0; i < size; i++) {
                tempArray[i] = strings[i];
            }
            strings = null;
            size = size + 1;
            strings = new String[size];
            for (int i = 0; i < size - 1; i++) {
                strings[i] = tempArray[i];
            }
        }
        strings[currIndex++] = titleIn;
    }
    public void delete(String titleIn) {
        boolean found = false;
        for (int i = 0; i < (currIndex - 1); i++) {
            if (found == false) {
                if (strings[i].equals(titleIn)) {
                    found = true;
                    strings[i] = strings[i + 1];
                }
            } else {
                if (i < (currIndex - 1)) {
                    strings[i] = strings[i + 1];
                } else {
                    strings[i] = null;
                }
            }
        }
        if (found == true) {
            --currIndex;
        }
    }
    public StringListIterator createIterator() {
        return new InnerIterator();
    }
    private class InnerIterator
            implements StringListIterator {

        private int pos = 0;

        private InnerIterator() {
        }
        public void first() {
            pos = 0;
        }
        public void next() {
            if (pos < (currIndex)) {
                ++pos;
            }
        }
        public boolean isDone() {
            if (pos >= (currIndex)) {
                return true;
            } else {
                return false;
            }
        }
        public String currentString() {
            return strings[pos];
        }
    }
}

public class Main {
    public static void main(String[] args) {
        StringList strings = new StringList(3);
        strings.append("string1");
        strings.append("string2");
        strings.append("string3");
        StringListIterator iterator =
                strings.createIterator();
        while (!iterator.isDone()) {
            String curr = iterator.currentString();
            System.out.println(curr);
            iterator.next();
        }
        strings.delete("string1");
        System.out.println(" ");
        iterator.first();
        while (!iterator.isDone()) {
            String curr = iterator.currentString();
            System.out.println(curr);
            iterator.next();
        }
    }
}

Le API standard di Java forniscono un meccanismo built-in che facilita l'uso del pattern Iterator. Ogni oggetto che implementa java.util.AbstractList (es.: Vector e ArrayList tanto per fare i nomi di due classi ampiamente usate nella programmazione java), esporta il metodo public java.util.Iterator iterator() che corrisponde, per funzionalità, al metodo public StringListIterator createIterator() della classe StringList dell'esempio appena visto. Facendo uso dell'interfaccia java.util.Iterator avremmo ottenuto il seguente listato:


import java.util.*;
public class Main {


Si noti che, essendo Iterator una classe di uso generico (applicabile ad aggregati di Oggetti di qualsiasi tipo), è necessario effettuare il cast a String dell'Object ritornato dal metodo iterator.next(). Nel nostro esempio il cast non è necessario perchè abbiamo definito un Iterator ad hoc il cui metodo currentString() ritorna una Stringa.


Nessun commento: