The iterator pattern of C + + design pattern _c language

Source: Internet
Author: User

Objective

At the end of the year, the time is really very fast ah. Recently also very sentimental, always miss college days, dream often dream. Dream of the university in front of the computer silly knocking on the keyboard, writing code, dealing with data structures and algorithms of the operation, the establishment of a linked list, traversing the list, print linked list. Now take a look at the header file of the linked list that was declared at that time:

Copy Code code as follows:

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

Look back, I wrote the code is a little bit do not know. Yes, at that time, is directly linked to the creation and traversal of the list in a class, is to facilitate, until that day to see the iterator design pattern, let me have a look back to re-examine the code I have written, the opportunity to understand their own shortcomings.

Iterator mode

In Gof's design pattern: The basics of reusable object-oriented software, this is true of the iterator pattern: Provides a way to access the elements of an aggregation object sequentially without exposing the internal representation of the object.

An aggregation object is a so-called object container; As a container, you should provide a way for others to access its elements, but, sometimes, I do not want to traverse the container to know how my container is implemented; As I did in college, the linked list provided only the traversal from the beginning to the end, if I needed to traverse from tail to head? Do I have to add the corresponding Method!!! The way the containers are traversed is so changeable that we don't know what the requirements are, if the requirements change, then our code will be a lot of changes, so we need to change; for the above code, when I iterate over the same list object many times, is there a m_pcurrent object confusion? Yes, all of this means that we have to decouple the internal structure of a container from its traversal, and we cannot face it if the above situation arises. Like the container in the STL, it decoupled the implementation and traversal of the object in the container, so we can't know how the object data is organized inside it, and we can go through the container in our own thoughts without any errors. Using the iterator pattern in our project is a good way to decouple the internal representation of the container object from its traversal. Next, we'll take a detailed summary of the iterator pattern.

UML Class Diagram

Iterator: Defines the interface of an iterator to access and traverse elements;
Concreteiterator: Implement the specific iterator;
Aggregate: A defined container that creates an interface to the corresponding iterator object;
Concreteaggregate: The concrete container implementation creates an interface for the corresponding iterator that returns an appropriate instance of the Concreteiterator.

Use occasion

1. Accessing the contents of an aggregated object without exposing its internal representation;
2. Supports multiple traversal of aggregated objects (from front to rear, back to front);
3. Provides a unified interface for traversing different aggregation structures, that is, to support polymorphic iterations.

Role

1. It supports the traversal of an aggregation in a different way, and can even define its own subclasses of iterators to support the new traversal;
2. The iterator simplifies the aggregation interface, and with the iterator's traversal interface, the aggregation itself no longer requires a similar traversal interface. This simplifies the aggregation interface;
3. There can be multiple traversal on the same aggregation, and each iterator keeps its own traversal state, so we can do multiple traversal at the same time.

Code implementation

Copy Code code 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
{
Public
virtual void (a) = 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 A-a ();
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 are 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;
}

A one-way linked list is implemented in the code to decouple the linked list from the iterator. For polymorphic iterations, add the abstract class Abstractjtlist, which is declared as follows:

Copy Code code as follows:

Class Abstractjtlist
{
Public
Virtual iterator *getiterator () const = 0;
};

Class Jtlist inherits the abstract class and implements Getiterator, as follows:

Copy Code code as follows:

Iterator *jtlist::getiterator () const
{
Return to New Jtlistiterator (this);
}

Well, in this case, there's no need to go to new jtlistiterator on the client, just like this:

Copy Code code as follows:

Iterator *piterator = Pjtlist->getiterator ();

That's perfectly fine, but there's another problem, and I'm new in Getiterator, and for the client, I don't know that this new operation exists, and the client will not be able to release this new memory, So how do you implement the automatic release of this memory? Well, in combination with the iterator model, the previous summary of the RAII mechanism again practical application.
According to the RAII mechanism, this iterator needs to be encapsulated so that it has the function of automatic release, and it has to take advantage of another class, as follows:

Copy Code code 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 it, it's like the following:

Copy Code code as follows:

Iteratorptr Piterator (Pjtlist->getiterator ());

This eliminates the hassle of releasing the iterator. Here is a total of three demo projects, providing complete demo project download. (Project download)

Summarize

The iterator pattern is a classic pattern. But just because it's so classic, if programmers are going to repeat the wheel every time, is a bit unreasonable, so, now the basic formation of the class library, are very good implementation of the iterator pattern, in the use of these class library provided by the container, do not need us to implement the corresponding iterator; it's like the STL. But then again said back, such a classic thing, you do not go to learn is not a pity ah, yes, in today's society, more than the pressure of the body. Well, always remember, the design pattern is an idea, not a constant, a thought, you know.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.