Итератор
Iterator
Назначение
Предоставляет способ последовательного доступа ко всем элементам составного объекта, не раскрывая его внутреннего представления.
Результаты
1. Сложные составные объекты можно обходить по-разному. Для изменения алгоритма обхода нужно определить подкласс класса Iterator и заменить один экземпляр итератора другим.
2. Итераторы упрощают интерфейс класса Aggregate.
3. Одновременно для данного агрегата может быть активно несколько обходов.
4. Модификация составного объекта в то время, как совершается его обход, может оказаться опасной. Для создания устойчивого к модификациям итератора необходимо изменять состояние всех созданных итераторов при вставке или удалении.
5. Если итерацией управляет клиент, то итератор называется внешним, в противном случае – внутренним. В случае внутреннего итератора клиент передает составному объекту некоторую операцию, а объект сам применяет эту операцию к каждому элементу. Внешние итераторы обладают большей гибкостью, чем внутренние. Например, сравнить две коллекции на равенство с помощью внешнего итератора очень легко, а с помощью внутреннего – практически невозможно.
Структура
Реализация
//
class Aggregate {
public:
virtual Iterator *CreateIterator()=0;
};
//
class Item;
//
class Aggregate1 : public Aggregate {
friend class Iterator1;
Item *items;
int size;
public:
Iterator1 *CreateIterator() { return new Iterator1(this); }
};
//
class Iterator {
public:
virtual void First()=0;
virtual void Next()=0;
virtual bool IsDone()=0;
virtual Item &CurrentItem()=0;
};
//
class Iterator1 {
friend class Aggregate1;
Aggregate1 *a;
int i;
Iterator1(Aggregate1 *);
public:
void First() { i=0; }
void Next() { ++i; }
bool IsDone() { return i>=a->size; }
Item &CurrentItem() { return a->items[i]; }
};
//
Aggregate *a;
Iterator *it=a->CreateIterator();
for(it->First();!it->IsDone();it->Next())
... действия с it->CurrentItem() ...
В STL для работы с итераторами используется перегрузка операций: для получения текущего элемента – операция разъадресации (*), для перехода на следующий элемент – операция инкремента (++), для проверки завершения – сравнение с со специальным итератором контейнера
end().
Внутренний итератор (см. также паттерн посетитель)
//
typedef int Item;
//
class Iterator {
public:
virtual void Operation(Item&)=0;
};
//
class Aggregate {
public:
virtual void ApplyIterator(Iterator &)=0;
};
//
class Aggregate1 : public Aggregate {
Item *items;
int size;
public:
void ApplyIterator(Iterator &)
{ for(int i=0;i<size;++i)
Iterator.Operation(items[i]);
}
};
//
class SumIterator : public Iterator {
int sum;
public:
SumIterator():sum(0) {}
void Operation(Item &it) { sum+=it; }
int getSum() const { return sum; }
} sumIt;
...
Aggregate *a;
a->ApplyIterator(sumIt);
cout<<sumIt->getSum();