欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++設(shè)計(jì)模式之迭代器模式

 更新時(shí)間:2014年10月08日 11:49:47   作者:果凍想  
這篇文章主要介紹了C++設(shè)計(jì)模式之迭代器模式,本文講解了什么是迭代器模式、迭代器模式的代碼實(shí)例等內(nèi)容,需要的朋友可以參考下

前言

又到年底了,時(shí)間真的過(guò)的好快啊。最近也非常感傷,總是懷念大學(xué)的日子,做夢(mèng)的時(shí)候也常常夢(mèng)到。夢(mèng)到大學(xué)在電腦前傻傻的敲著鍵盤,寫著代碼,對(duì)付著數(shù)據(jù)結(jié)構(gòu)與算法的作業(yè);建立一個(gè)鏈表,遍歷鏈表,打印鏈表?,F(xiàn)在把那個(gè)時(shí)候聲明的鏈表的頭文件拿出來(lái)看看:

復(fù)制代碼 代碼如下:

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

再回頭看看,自己寫的代碼都有點(diǎn)不認(rèn)識(shí)了。是的,那個(gè)時(shí)候,就是直接將鏈表的創(chuàng)建和遍歷都放在一類中,就是為了方便,直到那天看了迭代器設(shè)計(jì)模式,讓我有了一次回過(guò)頭來(lái)重新審視自己寫過(guò)的代碼,認(rèn)識(shí)自己的不足的機(jī)會(huì)。

迭代器模式

在GOF的《設(shè)計(jì)模式:可復(fù)用面向?qū)ο筌浖幕A(chǔ)》一書中對(duì)迭代器模式是這樣說(shuō)的:提供一種方法順序訪問(wèn)一個(gè)聚合對(duì)象中各個(gè)元素,而又不需要暴露該對(duì)象的內(nèi)部表示。

一個(gè)聚合對(duì)象,就是所謂的對(duì)象容器了;作為一個(gè)容器,都應(yīng)該提供一種方法來(lái)讓別人可以訪問(wèn)它的元素;但是,有的時(shí)候,我是不希望遍歷容器的人知道我的容器是如何實(shí)現(xiàn)的;那該怎么辦?就像我在大學(xué)那樣實(shí)現(xiàn)的鏈表,只提供了從頭到尾的遍歷,如果我需要從尾到頭的遍歷呢?是不是我又要添加對(duì)應(yīng)的方法了呢?。?!容器的遍歷方式千變?nèi)f化,我們不知道需求是如何的,如果需求變了,那么我們的代碼就會(huì)發(fā)生很大的改動(dòng),所以,我們需要去改變;對(duì)于上面的代碼,當(dāng)我對(duì)同一個(gè)鏈表對(duì)象進(jìn)行多次遍歷時(shí),是不是就出現(xiàn)了m_pCurrent對(duì)象混亂的局面呢?是的,這一切的一切,都說(shuō)明,我們必須去將一個(gè)容器的內(nèi)部結(jié)構(gòu)與它的遍歷進(jìn)行解耦,要是出現(xiàn)上面的情況時(shí),我們就無(wú)法面對(duì)。就好比STL中的容器,它將容器中對(duì)象的實(shí)現(xiàn)和遍歷很好的解耦了,所以,我們就無(wú)法知道它的內(nèi)部是如何組織對(duì)象數(shù)據(jù)的,同時(shí),我們也可以按照我們自己的想法去遍歷容器,而不會(huì)出現(xiàn)任何差錯(cuò)。在我們的項(xiàng)目中使用迭代器模式就能很好的將容器對(duì)象的內(nèi)部表示與對(duì)它的遍歷進(jìn)行解耦。接下來(lái),我們?cè)賮?lái)詳細(xì)的總結(jié)迭代器模式。

UML類圖

Iterator:定義迭代器訪問(wèn)和遍歷元素的接口;
ConcreteIterator:實(shí)現(xiàn)具體的迭代器;
Aggregate:定義的容器,創(chuàng)建相應(yīng)迭代器對(duì)象的接口;
ConcreteAggregate:具體的容器實(shí)現(xiàn)創(chuàng)建相應(yīng)迭代器的接口,該操作返回ConcreteIterator的一個(gè)適當(dāng)?shù)膶?shí)例。

使用場(chǎng)合

1.訪問(wèn)一個(gè)聚合對(duì)象的內(nèi)容而無(wú)需暴露它的內(nèi)部表示;
2.支持對(duì)聚合對(duì)象的多種遍歷(從前到后,從后到前);
3.為遍歷不同的聚合結(jié)構(gòu)提供一個(gè)統(tǒng)一的接口,即支持多態(tài)迭代。

作用

1.它支持以不同的方式遍歷一個(gè)聚合,甚至都可以自己定義迭代器的子類以支持新的遍歷;
2.迭代器簡(jiǎn)化了聚合的接口,有了迭代器的遍歷接口,聚合本身就不再需要類似的遍歷接口了。這樣就簡(jiǎn)化了聚合的接口;
3.在同一個(gè)聚合上可以有多個(gè)遍歷,每個(gè)迭代器保持它自己的遍歷狀態(tài);因此,我們可以同時(shí)進(jìn)行多個(gè)遍歷。

代碼實(shí)現(xiàn)

復(fù)制代碼 代碼如下:

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

代碼中實(shí)現(xiàn)了一個(gè)單向鏈表,將鏈表與迭代器解耦。對(duì)于多態(tài)迭代,添加抽象類AbstractJTList,聲明如下:

復(fù)制代碼 代碼如下:

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

類JTList繼承該抽象類,并實(shí)現(xiàn)GetIterator,如下:

復(fù)制代碼 代碼如下:

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

好了,這樣的話,在客戶端就不用去new JTListIterator了,只需要這樣:

復(fù)制代碼 代碼如下:

Iterator *pIterator = pJTList->GetIterator();

這就完全好了;但是,這樣又出現(xiàn)另外一個(gè)問(wèn)題,我在GetIterator中new了一個(gè)JTListIterator,對(duì)于客戶端來(lái)說(shuō),我并不知道這個(gè)new操作的存在,就會(huì)出現(xiàn)客戶端不會(huì)去釋放這個(gè)new開(kāi)辟的內(nèi)存,那么如何實(shí)現(xiàn)這個(gè)內(nèi)存的自動(dòng)釋放呢。好了,就結(jié)合迭代器模式,再將之前總結(jié)的RAII機(jī)制再實(shí)際運(yùn)用一次。
根據(jù)RAII機(jī)制,需要將這個(gè)迭代器進(jìn)行封裝,讓它具有自動(dòng)釋放的功能,就得借助另一個(gè)類,如下:

復(fù)制代碼 代碼如下:

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

我們?cè)谑褂玫臅r(shí)候,就像下面這樣:

復(fù)制代碼 代碼如下:

IteratorPtr pIterator(pJTList->GetIterator());

這樣就省去了釋放迭代器的麻煩了。這里一共涉及了三個(gè)DEMO工程,提供完整DEMO工程下載。(工程下載

總結(jié)

迭代器模式是一個(gè)很經(jīng)典的模式。但是,就是因?yàn)樗?jīng)典了,如果每次都要程序員去重復(fù)造輪子,就有點(diǎn)說(shuō)不過(guò)去了,所以,現(xiàn)在基本成型的類庫(kù),都非常好的實(shí)現(xiàn)了迭代器模式,在使用這些類庫(kù)提供的容器時(shí),并不需要我們親自去實(shí)現(xiàn)對(duì)應(yīng)的迭代器;就好比STL了。但是話又說(shuō)回來(lái)了,如此經(jīng)典的東西,你不去學(xué)習(xí)是不是很可惜?。皇前?,在當(dāng)今社會(huì),技多不壓身。好了,永遠(yuǎn)記住,設(shè)計(jì)模式是一種思想,并不是一層不變的,一種思想,你懂的。

相關(guān)文章

  • c語(yǔ)言執(zhí)行Hello?World背后經(jīng)歷的步驟

    c語(yǔ)言執(zhí)行Hello?World背后經(jīng)歷的步驟

    這篇文章介紹了c語(yǔ)言執(zhí)行Hello?World背后經(jīng)歷的步驟,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-12-12
  • C++深入講解哈夫曼樹(shù)

    C++深入講解哈夫曼樹(shù)

    給定N個(gè)權(quán)值作為N個(gè)葉子結(jié)點(diǎn),構(gòu)造一棵二叉樹(shù),若該樹(shù)的帶權(quán)路徑長(zhǎng)度達(dá)到最小,稱這樣的二叉樹(shù)為最優(yōu)二叉樹(shù),也稱為哈夫曼樹(shù)(Huffman Tree)。哈夫曼樹(shù)是帶權(quán)路徑長(zhǎng)度最短的樹(shù),權(quán)值較大的結(jié)點(diǎn)離根較近
    2022-05-05
  • C++ 設(shè)置和獲取當(dāng)前工作路徑的實(shí)現(xiàn)代碼

    C++ 設(shè)置和獲取當(dāng)前工作路徑的實(shí)現(xiàn)代碼

    這篇文章主要介紹了C++ 設(shè)置和獲取當(dāng)前工作路徑的實(shí)現(xiàn)代碼,防止DLL加載不到配置和文件,需要的朋友可以參考下
    2017-09-09
  • C++中的運(yùn)算符和表達(dá)式

    C++中的運(yùn)算符和表達(dá)式

    這篇文章主要介紹了C++中的運(yùn)算符和表達(dá)式,學(xué)習(xí)使用表達(dá)式,對(duì)數(shù)據(jù)類型進(jìn)行處理.詳細(xì)介紹內(nèi)容需要的小伙伴可以參考下面文章相關(guān)內(nèi)容
    2022-03-03
  • Qt讀取Json文件的方法詳解(含源碼+注釋)

    Qt讀取Json文件的方法詳解(含源碼+注釋)

    QT本身就有讀取json的接口,簡(jiǎn)單又方便,下面這篇文章主要給大家介紹了關(guān)于Qt讀取Json文件(含源碼+注釋)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-10-10
  • C++控制臺(tái)用定時(shí)器實(shí)例代碼

    C++控制臺(tái)用定時(shí)器實(shí)例代碼

    這篇文章主要介紹了C++控制臺(tái)用定時(shí)器實(shí)例代碼,分享了相關(guān)代碼示例,小編覺(jué)得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-02-02
  • C語(yǔ)言制作貪吃蛇小游戲

    C語(yǔ)言制作貪吃蛇小游戲

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言制作貪吃蛇小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • c++ 面向?qū)ο笤O(shè)計(jì)五大原則

    c++ 面向?qū)ο笤O(shè)計(jì)五大原則

    這篇文章主要介紹了c++ 面向?qū)ο笤O(shè)計(jì)五大原則,幫助大家更好的理解和學(xué)習(xí)c++面向?qū)ο笤O(shè)計(jì),感興趣的朋友可以了解下
    2020-08-08
  • C++ boost::asio編程-異步TCP詳解及實(shí)例代碼

    C++ boost::asio編程-異步TCP詳解及實(shí)例代碼

    這篇文章主要介紹了C++ boost::asio編程-異步TCP詳解及實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下
    2016-11-11
  • C語(yǔ)言 以數(shù)據(jù)塊的形式讀寫文件詳解及實(shí)現(xiàn)代碼

    C語(yǔ)言 以數(shù)據(jù)塊的形式讀寫文件詳解及實(shí)現(xiàn)代碼

    本文主要介紹 C語(yǔ)言 以數(shù)據(jù)塊的形式讀寫文件,這里對(duì)相關(guān)知識(shí)資料做了整理,并附代碼示例,以便大家學(xué)習(xí)參考,有學(xué)習(xí)此部分知識(shí)的朋友可以參考下
    2016-08-08

最新評(píng)論