DesignPatterns_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];
};

// 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.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章