/////////////////////////////////////////////////////////////////////////////////////////
// Iterator
// - Provide a way to access the elements of an aggregate object sequentially without
// exposing its underlying representation.
//
// Author : ZAsia
// Date : 15/05/14
// Warning : In practice, declaration and implementation should
// be separated(.h and .cpp).
/////////////////////////////////////////////////////////////////////////////////////////
#include
using namespace std;
#define DEFAULT_CAPACITY 128
// Iterator
// - defines an interface for accessing and traversing elements.
template
class Iterator
{
public:
virtual void First() = 0;
virtual void Next() = 0;
virtual bool IsDone() const = 0;
virtual Item CurrentItem() const = 0;
};
// forward declaration
template
class ConcreteAggregate;
// ConcreteIterator
// - implements the Iterator interface.
// - keep the track of the current position in the traversal of the aggregate.
//////////
// - the implementation of ReverseIterator is identical, except its First operation
// positions _current to the end of the ConcreteAggregate, and Next decrements
// _current toward the first item.
template
class ConcreteIterator : public Iterator
{
public:
ConcreteIterator(const ConcreteAggregate *aggr) :
_aggr(aggr), _current(0) { }
// First positions the iterator to the first element.
virtual void First()
{
_current = 0;
}
// Next advances the current element.
virtual void Next()
{
if (_current < _aggr->Count())
{
++_current;
}
}
// IsDone checks whether the index refers to an element within the List.
virtual bool IsDone() const
{
return _current >= _aggr->Count();
}
// CurrentItem returns the item at the current index.
// If the iteration has already terminated, then throw an exception.
virtual Item CurrentItem() const
{
if (IsDone())
{
cout << "Iterator out of bounds." << endl;
return 0;
}
return _aggr->Get(_current);
}
private:
const ConcreteAggregate *_aggr;
long _current;
};
// Aggregate
// - defines an interface for creating an Iterator object.
template
class Aggregate
{
public:
Aggregate( ) { }
virtual ~Aggregate() { }
virtual ConcreteIterator *CreateIterator() = 0;
virtual void Append(Item item) = 0;
virtual void Remove(Item item) = 0;
virtual long Count() const = 0;
virtual Item Get(long index) const = 0;
};
// ConcreteAggregate
// - implements the Iterator creation interface to return an instance of the
// proper ConcreteIterator.
template
class ConcreteAggregate : public Aggregate
{
public:
ConcreteAggregate() : _size(0), _iter(nullptr) { }
virtual ConcreteIterator *CreateIterator()
{
if (_iter)
{
return _iter;
}
return new ConcreteIterator(this);
}
virtual void Append(Item item)
{
if (_size > DEFAULT_CAPACITY)
{
cout << "Aggregate out of capacity." << endl;
return;
}
_arr[_size++] = item;
}
virtual void Remove(Item item)
{
if (_size == 0)
{
return;
}
for (int i = 0; i < _size; ++i)
{
if (_arr[i] == item)
{
for (int j = i; j < _size - 1; ++j)
{
_arr[j] = _arr[j + 1];
}
--_size;
}
}
}
virtual long Count() const
{
return _size;
}
virtual Item Get(long index) const
{
return _arr[index];
}
private:
ConcreteIterator *_iter;
long _size;
Item _arr[DEFAULT_CAPACITY];
};
// Collaborations
// - A ConcreteIterator keeps track of the current object in the aggregate and
// can compute the succeeding object in the traversal.
int main()
{
ConcreteAggregate aggregate;
for (long item = 0; item < 21; ++item)
{
aggregate.Append(item);
}
aggregate.Remove(15);
ConcreteIterator *pIterator = aggregate.CreateIterator();
for (pIterator->First(); !pIterator->IsDone(); pIterator->Next())
{
cout << pIterator->CurrentItem() << endl;
}
if (pIterator)
{
delete pIterator;
pIterator = nullptr;
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////////
// 1. How robust is the iterator? It can be dangerous to modify an aggregate while
// you'r traversing it. A robust iterator most rely on registering the iterator
// with the aggregate. On insertion or removal, the aggregate either adjusts the
// internal state of iterators it has produced, or it maintains information
// internally to ensure proper traversal.
// 2. Polymorphic iterators have another drawback: the client is responsible for
// deleting them. This is error-prone, because it's easy to forget to free a
// heap-allocated when you're finished with it. And if an exception is triggered,
// the iterator object will never be freed.
// 1. Making sure iterators get deleted. Notice that CreateIterator returns a
// newly allocated iterator object. We're responsible for deleting it. If
// we forget, then we've created storage leak. To make life easier for client,
// we'll provide an IteratorPtr that acts as a proxy for an iterator. It takes
// care of cleaning up the Iterator object when it goes out of scope.
// 2. IteratorPtr is always allocated on the stack. C++ automatically takes care
// of calling its destructor, which deletes the real iterator.
/////////////////////////////////////////////////////////////////////////////////////////
// Iterator
// - Provide a way to access the elements of an aggregate object sequentially without
// exposing its underlying representation.
//
// Author : ZAsia
// Date : 15/05/14
// Warning : In practice, declaration and implementation should
// be separated(.h and .cpp).
/////////////////////////////////////////////////////////////////////////////////////////
#include
using namespace std;
#define DEFAULT_CAPACITY 128
// Iterator
// - defines an interface for accessing and traversing elements.
template
class Iterator
{
public:
virtual void First() = 0;
virtual void Next() = 0;
virtual bool IsDone() const = 0;
virtual Item CurrentItem() const = 0;
};
// forward declaration
template
class ConcreteAggregate;
// ConcreteIterator
// - implements the Iterator interface.
// - keep the track of the current position in the traversal of the aggregate.
//////////
// - the implementation of ReverseIterator is identical, except its First operation
// positions _current to the end of the ConcreteAggregate, and Next decrements
// _current toward the first item.
template
class ConcreteIterator : public Iterator
{
public:
ConcreteIterator(const ConcreteAggregate *aggr) :
_aggr(aggr), _current(0) { }
// First positions the iterator to the first element.
virtual void First()
{
_current = 0;
}
// Next advances the current element.
virtual void Next()
{
if (_current < _aggr->Count())
{
++_current;
}
}
// IsDone checks whether the index refers to an element within the List.
virtual bool IsDone() const
{
return _current >= _aggr->Count();
}
// CurrentItem returns the item at the current index.
// If the iteration has already terminated, then throw an exception.
virtual Item CurrentItem() const
{
if (IsDone())
{
cout << "Iterator out of bounds." << endl;
return 0;
}
return _aggr->Get(_current);
}
private:
const ConcreteAggregate *_aggr;
long _current;
};
// Aggregate
// - defines an interface for creating an Iterator object.
template
class Aggregate
{
public:
Aggregate( ) { }
virtual ~Aggregate() { }
virtual ConcreteIterator *CreateIterator() = 0;
virtual void Append(Item item) = 0;
virtual void Remove(Item item) = 0;
virtual long Count() const = 0;
virtual Item Get(long index) const = 0;
};
// ConcreteAggregate
// - implements the Iterator creation interface to return an instance of the
// proper ConcreteIterator.
template
class ConcreteAggregate : public Aggregate
{
public:
ConcreteAggregate() : _size(0), _iter(nullptr) { }
virtual ConcreteIterator *CreateIterator()
{
if (_iter)
{
return _iter;
}
return new ConcreteIterator(this);
}
virtual void Append(Item item)
{
if (_size > DEFAULT_CAPACITY)
{
cout << "Aggregate out of capacity." << endl;
return;
}
_arr[_size++] = item;
}
virtual void Remove(Item item)
{
if (_size == 0)
{
return;
}
for (int i = 0; i < _size; ++i)
{
if (_arr[i] == item)
{
for (int j = i; j < _size - 1; ++j)
{
_arr[j] = _arr[j + 1];
}
--_size;
}
}
}
virtual long Count() const
{
return _size;
}
virtual Item Get(long index) const
{
return _arr[index];
}
private:
ConcreteIterator *_iter;
long _size;
Item _arr[DEFAULT_CAPACITY];
};
// IteratorPtr
// 1. Making sure iterators get deleted. Notice that CreateIterator returns a
// newly allocated iterator object. We're responsible for deleting it. If
// we forget, then we've created storage leak. To make life easier for client,
// we'll provide an IteratorPtr that acts as a proxy for an iterator. It takes
// care of cleaning up the Iterator object when it goes out of scope.
// 2. IteratorPtr is always allocated on the stack. C++ automatically takes care
// of calling its destructor, which deletes the real iterator.
template
class IteratorPtr
{
public:
IteratorPtr(Iterator *i) : _i(i) { }
~IteratorPtr() { delete _i; }
Iterator *operator->() { return _i; }
Iterator &operator*() { return *_i; }
private:
// disallow copy and assignment to avoid multiple deletions of _i
IteratorPtr(const IteratorPtr &ip) { }
IteratorPtr &operator=(const IteratorPtr &rs) { }
private:
Iterator *_i;
};
// Collaborations
// - A ConcreteIterator keeps track of the current object in the aggregate and
// can compute the succeeding object in the traversal.
int main()
{
ConcreteAggregate aggregate;
for (long item = 0; item < 21; ++item)
{
aggregate.Append(item);
}
aggregate.Remove(15);
// ConcreteIterator *pIterator = aggregate.CreateIterator();
IteratorPtr iterator(aggregate.CreateIterator());
for (iterator->First(); !iterator->IsDone(); iterator->Next())
{
cout << iterator->CurrentItem() << endl;
}
// if (pIterator)
// {
/// delete pIterator;
// pIterator = nullptr;
// }
return 0;
}
///////////////////////////////////////////////////////////////////////////////////
// 1. How robust is the iterator? It can be dangerous to modify an aggregate while
// you'r traversing it. A robust iterator most rely on registering the iterator
// with the aggregate. On insertion or removal, the aggregate either adjusts the
// internal state of iterators it has produced, or it maintains information
// internally to ensure proper traversal.
// 2. Polymorphic iterators have another drawback: the client is responsible for
// deleting them. This is error-prone, because it's easy to forget to free a
// heap-allocated when you're finished with it. And if an exception is triggered,
// the iterator object will never be freed.