C ++のデザインパターンのIterator

イテレータパターン

GOFでは「デザインパターン:再利用可能なオブジェクト指向ソフトウェアの要素」反復モードの本は言うことです:各要素高分子体へのシーケンシャルアクセスの方法が提供されていますが、対象物の内部を公開する必要はありません。表現。

コンテナとして、他の人にその要素へのアクセスを許可する方法を提供しなければならない;高分子体は、オブジェクトコンテナアップと呼ばれますが、時々、私は人々は知られたくない私は、コンテナ船がどのようにトラバース実施、その後、どのように行うには?私はそれを横断する必要があれば、大学のリストには、唯一の尾から頭まで、最初から最後までトラバース提供するということ?実感のように 私はそれに対応する方法ではありません追加する必要があります!刻々と変化するのトラバーサルコンテナ我々のコードは変更が起こるの多くになりますので、ニーズは私たちは変更する必要があり、変更されている場合、我々は、需要があるかわからない、上記のコードのために、私は同じリストオブジェクトにあったときとき複数のパス、オブジェクトがm_pCurrentの混乱にそれを登場されていませんか?はい、すべてのすべてで、示していた、我々は内部の血管の構造とデカップリングのそのトラバーサル、および上記のような状況が発生した場合、我々はできない顔に行かなければなりません。STLコンテナ、そして我々はそれがオブジェクトの内部データを整理する方法を知ることができないので、それは、コンテナオブジェクトの非常に優れたデカップリングを横断します、と私たちは私たち自身のアイデアに応じて行くことができることを実現同様エラーなしで、コンテナを横断します。私たちのプロジェクトにイテレータパターンを使用すると、コンテナ内のオブジェクトの良い表現がそのトラバーサルから切り離されることができます。次は、私たちに詳細な要約イテレータパターンをしてみましょう。

UML类图

反復子:反復子のアクセスを定義し、インターフェースの要素をトラバース;
ConcreteIterator:特定のイテレータを実装;
骨:コンテナの定義、対応するイテレータオブジェクトのインターフェースを作成するステップと、
ConcreteAggregate:特定のコンテナ実装は、操作リターンに対応するイテレータインターフェイスを作成ConcreteIteratorの適当な例。

 

機会を利用して

  1. その内部表現を公開せず、コンテンツオブジェクトの重合にアクセスします。
  2. ポリマー支持体オブジェクトの複数トラバーサル(背面から前面へ戻るフロント)。
  3. 異なるポリマー構造を横断する多型反復をサポートする統一されたインタフェースです。

 

効果

  1. これは、重合を通過するさまざまな方法をサポートしています、でも新しいトラバーサルをサポートするために、独自のイテレータのサブクラスを定義することができます。
  2. 反復子重合と同様のインターフェースを横切る重合自体がもはや必要性を横断しないようにイテレータとのインターフェース、インターフェースを簡素化。これは、界面重合を簡素化します。
  3. 同じ重合でトラバースを複数有していてもよく、各反復は、それ自身のトラバーサル状態を維持するため、我々は、同時に複数の横断できます。

 

以下のように、リストを反復を実装します。

#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;
}

コードは単独でリンクリストを実装し、リンクリストのイテレータはデカップリング。多型の反復のために、抽象クラスAbstractJTList、次のステートメントを追加します。

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

JTListクラスは抽象クラスを継承し、次のように、GetIteratorを実装します。

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

まあ、これはそうでは、クライアントはちょうどこのように、新しいJTListIteratorを持っていないです。

Iterator *pIterator = pJTList->GetIterator();

この完全に治癒しますが、これは別の質問を浮上している、私は新しいGetIteratorでJTListIteratorは、クライアントのために、私はこの新しい操作の存在を知らない、クライアントは、このリリースに行くことはありませんが存在します新しいオープンメモリは、これを実現する方法のメモリを自動的にまだリリース。まあ、反復モードと組み合わせて、その後の要約前RAIIメカニズム再び実用化。

RAIIメカニズム、次のようにイテレータは、別のクラスの手段を持って、それが自動的に解放する機能を提供し、パッケージ化する必要があります。

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

我々はこのように、使用する場合:

IteratorPtr pIterator(pJTList->GetIterator());

これは、イテレータの解除の手間がなくなります。

 

概要

イテレータパターンは、古典的なパターンです。しかし、それはホイールを作成するたびに、プログラマを繰り返した場合、それは今、正当化される、ライ​​ブラリーの基本的な形状あまりにも古典的であるため、反復モードの非常に良い実装され、これらのライブラリを使用しますコンテナを提供し、我々は、対応するイテレータを達成するために行く必要はありません。STLのように。しかし、その後、再び、あなたが学ばない古典的なところは、それは同情のああではない、それはより多くのボディよりも技術、今日の社会では、あります。まあ、常にそのデザインパターンのアイデアではなく、同じの層、アイデアであることを覚えている、あなたが知っています。

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

おすすめ

転載: blog.csdn.net/tianguiyuyu/article/details/103913808