C++設計形式之迭代器形式。本站提示廣大學習愛好者:(C++設計形式之迭代器形式)文章只能為提供參考,不一定能成為您想要的結果。以下是C++設計形式之迭代器形式正文
媒介
又到歲尾了,時光真的過的好快啊。比來也異常感傷,老是思念年夜學的日子,做夢的時刻也經常夢到。夢到年夜學在電腦前傻傻的敲著鍵盤,寫著代碼,對於著數據構造與算法的功課;樹立一個鏈表,遍歷鏈表,打印鏈表。如今把誰人時刻聲明的鏈表的頭文件拿出來看看:
typedef struct tagNode
{
int value;
tagNode *pPre;
tagNode *pNext;
}Node;
class CList
{
public:
CList();
CList(size_t n);
~CList();
bool PushBack(int value);
bool PopBack(int &value);
bool Insert(int pos, int value);
bool Delete(int pos);
bool IsEmpty();
int GetLength();
void Print();
// To iterate the list
bool HasNext();
int Next();
private:
int m_iLength;
Node *m_pCurrent;
Node *m_pHead;
Node *m_pTail;
};
再回頭看看,本身寫的代碼都有點不熟悉了。是的,誰人時刻,就是直接將鏈表的創立和遍歷都放在一類中,就是為了便利,直到那天看了迭代器設計形式,讓我有了一次回過火來從新審閱本身寫過的代碼,熟悉本身的缺乏的機遇。
迭代器形式
在GOF的《設計形式:可復用面向對象軟件的基本》一書中對迭代器形式是如許說的:供給一種辦法次序拜訪一個聚合對象中各個元素,而又不須要裸露該對象的外部表現。
一個聚合對象,就是所謂的對象容器了;作為一個容器,都應當供給一種辦法來讓他人可以拜訪它的元素;然則,有的時刻,我是不願望遍歷容器的人曉得我的容器是若何完成的;那該怎樣辦?就像我在年夜學那樣完成的鏈表,只供給了從頭至尾的遍歷,假如我須要從尾到頭的遍歷呢?是否是我又要添加對應的辦法了呢!!!容器的遍歷方法千變萬化,我們不曉得需求是若何的,假如需求變了,那末我們的代碼就會產生很年夜的修改,所以,我們須要去轉變;關於下面的代碼,當我對統一個鏈表對象停止屢次遍用時,是否是就湧現了m_pCurrent對象凌亂的局勢呢?是的,這一切的一切,都解釋,我們必需去將一個容器的外部構造與它的遍歷停止解耦,如果湧現下面的情形時,我們就沒法面臨。就比如STL中的容器,它將容器中對象的完成和遍歷很好的解耦了,所以,我們就沒法曉得它的外部是若何組織對象數據的,同時,我們也能夠依照我們本身的設法主意去遍歷容器,而不會湧現任何錯誤。在我們的項目中應用迭代器形式就可以很好的將容器對象的外部表現與對它的遍歷停止解耦。接上去,我們再來具體的總結迭代器形式。
UML類圖
Iterator:界說迭代器拜訪和遍歷元素的接口;
ConcreteIterator:完成詳細的迭代器;
Aggregate:界說的容器,創立響應迭代器對象的接口;
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
{
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
{
// The min index is 0, max index is 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 (pNode == m_pHead) // If the deleting node is head node
{
Node *pNewHead = m_pHead->pNext;
m_pHead = pNewHead;
}
else
{
// To get the deleting node's previous node
Node *pPreviousNode = NULL;
Node *pCurrentNode = m_pHead;
while (pCurrentNode)
{
pPreviousNode = pCurrentNode;
pCurrentNode = pCurrentNode->pNext;
if (pCurrentNode == pNode)
{
break;
}
}
// To get the deleting node's next node
Node *pNextNode = pNode->pNext;
// If pNextNode is NULL, it means the deleting node is the tail node, we should change the m_pTail pointer
if (pNextNode == NULL)
{
m_pTail = pPreviousNode;
}
// Relink the list
pPreviousNode->pNext = pNextNode;
}
// Delete the node
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()
{
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);
// Print the list by JTListIterator
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;
}
}
// Print the list by JTListIterator
for (pIterator->First(); !pIterator->IsDone(); pIterator->Next())
{
cout<<pIterator->CurrentItem()->value<<"->";
}
cout<<"NULL"<<endl;
delete pIterator;
delete pJTList;
return 0;
}
代碼中完成了一個單向鏈表,將鏈表與迭代器解耦。關於多態迭代,添加籠統類AbstractJTList,聲明以下:
class AbstractJTList
{
public:
virtual Iterator *GetIterator() const = 0;
};
類JTList繼續該籠統類,並完成GetIterator,以下:
Iterator *JTList::GetIterator() const
{
return new JTListIterator(this);
}
好了,如許的話,在客戶端就不消去new JTListIterator了,只須要如許:
Iterator *pIterator = pJTList->GetIterator();
這就完整好了;然則,如許又湧現別的一個成績,我在GetIterator中new了一個JTListIterator,關於客戶端來講,我其實不曉得這個new操作的存在,就會湧現客戶端不會去釋放這個new開拓的內存,那末若何完成這個內存的主動釋放呢。好了,就聯合迭代器形式,再將之前總結的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());
如許就省去了釋放迭代器的費事了。這裡一共觸及了三個DEMO工程,供給完全DEMO工程下載。(工程下載)
總結
迭代器形式是一個很經典的形式。然則,就是由於它太經典了,假如每次都要法式員去反復造輪子,就有點說不外去了,所以,如今根本成型的類庫,都異常好的完成了迭代器形式,在應用這些類庫供給的容器時,其實不須要我們親身去完成對應的迭代器;就比如STL了。然則話又說回來了,如斯經典的器械,你不去進修是否是很惋惜啊;是吧,在現今社會,技多不壓身。好了,永久記住,設計形式是一種思惟,其實不是一層不變的,一種思惟,你懂的。