c ++ Design Patterns Iterator

Iterator pattern

In the GOF "Design Patterns: Elements of Reusable Object-Oriented Software" book on an iterative mode is to say: there is provided a method of sequential access to each element a polymeric object, but does not need to expose the interior of the object representation.

A polymeric object is called object container up; as a container, should provide a way to allow others access to its elements; but, sometimes, I do not want people to know I traverse the container vessel is how implementation; then how to do? Like I realize that in the list of universities, provides only traversed from start to finish, from the tail to the head if I needed to traverse it? I have to add is not a corresponding method of it! ! ! Traversal container of ever-changing, we do not know what the demand is, if needs have changed, so our code will be a lot of changes happen, so we need to change; for the above code, when I was on the same list object when multiple passes, is not the object appeared m_pCurrent chaos it? Yes, all in all, were indicative, we have to go to the internal structure of a container with its traversal of decoupling, when and if the above situation occurs, we can not face. Like the STL containers, and realize that it will traverse a very good decoupling of the container object, so we can not know how it is to organize the internal data of the object, and we can go according to our own ideas traverse the container, without any errors. Using an iterator pattern in our project can be a good representation of the object inside the container will be decoupled from its traversal. Next, let us detailed summary iterator pattern.

UML 类图

Iterator: define iterator access and traverse the elements of the interface;
ConcreteIterator: implement particular iterator;
Aggregate: definition of container, creating the corresponding iterator object interface;
ConcreteAggregate: specific container implementation creates the corresponding iterator interface, the operation returns suitable examples of a ConcreteIterator.

 

Using the occasion

  1. Accessing a content object polymerization without exposing its internal representation;
  2. Polymeric supports more traversal of the object (front to back, from back to front);
  3. Traversing the different polymeric structure is a unified interface, which is to support polymorphic iteration.

 

effect

  1. It supports different ways to traverse a polymerization, can even define their own iterator subclasses to support new traversal;
  2. Iterator polymerization simplified interfaces, interfaces with iterators to traverse the polymerization itself, there is no need of an interface similar traversed. This simplifies the interface polymerization;
  3. In the same polymerization may have a plurality of traverse, each iteration maintains its own traversal state; therefore, we can traverse a plurality of simultaneously.

 

Implement a iterates over the list, as follows:

#include<iostream>
using namespace std;

typedef struct tagNode
{
	int value;
	tagNode* pNext;
}Node;


//列表类
class JTList
{
public:

	JTList()
	{
		m_pHead = NULL;
		m_pTail = NULL;
	}
	JTList(const JTList&);
	~JTList();
	JTList& operator=(const JTList &);

	long GetCount() const;
	Node* Get(const long index) const;
	Node* First() const;
	Node* Last() const;
	bool Includes(const int&) const;

	void Append(const int &);
	void Remove(Node* pNode);
	void RemoveAll();

private:
	Node* m_pHead;
	Node* m_pTail;
	long m_lCount;
};

class Iterator  //这就是一个对list的迭代器
{
public:
	virtual void First() = 0;
	virtual void Next() = 0;
	virtual bool IsDone() const = 0;
	virtual Node* CurrentItem() const = 0;
};

class JTListIterator :public Iterator
{
public:
	JTListIterator(JTList* pList)
	{
		m_pJTList = pList;
		m_pCurrent = NULL;
	}
	virtual void First();
	virtual void Next();
	virtual bool IsDone() const;
	virtual Node* CurrentItem() const;

private:
	JTList* m_pJTList;
	Node* m_pCurrent;
};

JTList::~JTList()
{
	Node* pCurrent = m_pHead;
	Node* pNextNode = NULL;

	while (pCurrent)
	{
		pNextNode = pCurrent->pNext;
		delete pCurrent;
		pCurrent = pNextNode;
	}
}

long JTList::GetCount() const
{
	return m_lCount;
}

Node* JTList::Get(const long index) const
{
	//最小的索引是0,最大的索引是count-1
	if (index > m_lCount - 1 || index < 0)
	{
		return NULL;
	}

	int iPosTemp = 0;
	Node* pNodeTemp = m_pHead;
	while (pNodeTemp)
	{
		if (index == iPosTemp++)
		{
			return pNodeTemp;
		}
		pNodeTemp = pNodeTemp->pNext;
	}
	return NULL;
}

Node* JTList::First() const
{
	return m_pHead;
}

Node* JTList::Last() const
{
	return m_pTail;
}

bool JTList::Includes(const int& value) const
{
	Node* pNodeTemp = m_pHead;
	while (pNodeTemp)
	{
		if (value == pNodeTemp->value)
		{
			return true;
		}
		pNodeTemp = pNodeTemp->pNext;
	}
	return false;
}

void JTList::Append(const int& value)
{
	//create the new node
	Node* pInsertNode = new Node();
	pInsertNode->value = value;
	pInsertNode->pNext = NULL;

	//This list is empty
	if (m_pHead == NULL)
	{
		m_pHead = m_pTail = pInsertNode;
	}
	else
	{
		m_pTail->pNext = pInsertNode;
		m_pTail = pInsertNode;
	}
	++m_lCount;
}


void JTList::Remove(Node* pNode)
{
	if (pNode == NULL || m_pHead == NULL || m_pTail == NULL)
	{
		return;
	}

	//if the deleting node is head node
	if (pNode == m_pHead)
	{
		Node* pNewHead = m_pHead->pNext;
		m_pHead = pNewHead;
	}
	else
	{
		Node* pPreviousNode = NULL;
		Node* pCurrentNode = m_pHead;
		while (pCurrentNode)
		{
			pPreviousNode = pCurrentNode;
			pCurrentNode = pCurrentNode->pNext;
			if (pCurrentNode == pNode)
			{
				break;
			}
		}

		Node* pNextNode = pNode->pNext;

		if (pNextNode == NULL)
		{
			m_pTail = pPreviousNode;
		}

		//Relink the list
		pPreviousNode->pNext = pNextNode;
	}

	delete pNode;
	pNode = NULL;
	--m_lCount;
}


void JTList::RemoveAll()
{
	delete this;
}

void JTListIterator::First()
{
	m_pCurrent = m_pJTList->First();
}

void JTListIterator::Next()
{
	m_pCurrent = m_pCurrent->pNext;
}

bool JTListIterator::IsDone() const
{
	return m_pCurrent == m_pJTList->Last()->pNext;
}

Node* JTListIterator::CurrentItem() const
{
	return m_pCurrent;
}


int main(int argc, char* argv[])
{
	JTList* pJTList = new JTList();
	pJTList->Append(10);
	pJTList->Append(20);
	pJTList->Append(30);
	pJTList->Append(40);
	pJTList->Append(50);
	pJTList->Append(60);
	pJTList->Append(70);
	pJTList->Append(80);
	pJTList->Append(90);
	pJTList->Append(100);

	Iterator* pIterator = new JTListIterator(pJTList);  //迭代器

	//打印链表
	for (pIterator->First(); !pIterator->IsDone(); pIterator->Next())
	{
		cout << pIterator->CurrentItem()->value << "->";
	}
	cout << "NULL" << endl;

	//Test for removing
	Node* pDeleteNode = NULL;
	for (pIterator->First(); !pIterator->IsDone(); pIterator->Next())
	{
		pDeleteNode = pIterator->CurrentItem();
		if (pDeleteNode->value == 100)
		{
			pJTList->Remove(pDeleteNode);
			break;
		}
	}

	for (pIterator->First(); !pIterator->IsDone(); pIterator->Next())
	{
		cout << pIterator->CurrentItem()->value << "->";
	}

	cout << "NULL" << endl;
	delete pIterator;
	delete pJTList;
}

Code implements a singly linked list, the linked list iterators decoupled. For polymorphic iteration, add an abstract class AbstractJTList, the following statement:

class AbstractJTList
{
public:
     virtual Iterator *GetIterator() const = 0;
};

JTList class inherit the abstract class and implement GetIterator, as follows:

Iterator *JTList::GetIterator() const
{
     return new JTListIterator(this);
}

Well, this is the case, the client will not have a new JTListIterator, just like this:

Iterator *pIterator = pJTList->GetIterator();

This completely healed; however, this has emerged another question, I new a JTListIterator in GetIterator, for a client, I do not know the existence of this new operation, there will be client will not go to this release new open memory, the memory of how to achieve this automatically released yet. Well, combined with an iterative mode, and then before the summary of RAII mechanism then the practical application again.

The RAII mechanism, the iterator will need to be packaged, it provides an automatic releasing function, have another class means, as follows:

class IteratorPtr
{
public:
     IteratorPtr(Iterator *pIterator) : m_pIterator(pIterator){}
     ~IteratorPtr() { delete m_pIterator; }
 
     Iterator *operator->(){ return m_pIterator; }
     Iterator &operator*() { return *m_pIterator; }
 
private:
     IteratorPtr(const IteratorPtr &);
     IteratorPtr &operator=(const IteratorPtr &);
     void *operator new(size_t size);
     void operator delete(void *);
 
private:
     Iterator *m_pIterator;
};

When we use, like this:

IteratorPtr pIterator(pJTList->GetIterator());

This eliminates the hassle of release of the iterator.

 

to sum up

Iterator pattern is a classic pattern. However, because it is too classic, if repeated every time a programmer to create the wheel, it is justified, so now the basic shape of the library, are very good implementation of the iterative mode, use these libraries providing a container, we do not need to go to achieve the corresponding iterator; like the STL. But then again, such a classic thing, you do not learn is not it a pity ah; it is, in today's society, technology more than body. Well, always remember that design pattern is an idea, not a layer of the same, an idea, you know.

发布了199 篇原创文章 · 获赞 77 · 访问量 20万+

Guess you like

Origin blog.csdn.net/tianguiyuyu/article/details/103913808