Definition: The iterator mode provides a method to access each element in an aggregate object sequentially without exposing its internal representation.
Scenario: we have two aggregate A and B, and there is an aggregate management class, including aggregate A and B, the function of this management class is to traverse the elements contained in the aggregation in sequence and print them to the console. Elements in each aggregation are stored in different ways. Some use arrays and some may be vectors or lists. Therefore, I have defined an iterator for each aggregation, the management class only needs to get the iterators of each aggregation in sequence, and use the iterator to traverse the elements, without having to worry about the storage mode of elements in the aggregation.
Class diagram:
The C ++ code is as follows:
#include <iostream>
#include <vector>
using namespace std;
#define COUNT 5
class Iterator
{
public:
virtual bool hasNext() = 0;
virtual int next() = 0;
};
class Menu
{
public:
virtual Iterator* createIterator() = 0;
};
class CAggregateAIter : public Iterator
{
public:
CAggregateAIter(vector<int> vData);
bool hasNext();
int next();
private:
vector<int> m_vData;
int m_iPosition;
};
class CAggregateBIter : public Iterator
{
public:
CAggregateBIter(int* piData);
bool hasNext();
int next();
private:
int m_iPosition;
int m_iData[COUNT];
};
class CAggregateA : public Menu
{
public:
CAggregateA();
Iterator* createIterator();
private:
vector<int> m_vData;
};
class CAggregateB : public Menu
{
public:
CAggregateB();
Iterator* createIterator();
private:
int m_iData[COUNT];
};
class AggregateMg
{
public:
void printAggr();
void printAggr(Iterator* piter);
private:
CAggregateA m_aggrA;
CAggregateB m_aggrB;
};
CAggregateAIter::CAggregateAIter(vector<int> vData)
{
m_iPosition = 0;
for (int i=0; i<vData.size(); ++i)
{
m_vData.push_back(vData.at(i));
}
}
bool CAggregateAIter::hasNext()
{
if (m_iPosition < m_vData.size())
{
return true;
}
else
{
return false;
}
}
int CAggregateAIter::next()
{
int iData = m_vData.at(m_iPosition);
++m_iPosition;
return iData;
}
CAggregateBIter::CAggregateBIter(int* piData)
{
m_iPosition = 0;
for (int i=0; i<COUNT; ++i)
{
m_iData[i] = piData[i];
}
}
bool CAggregateBIter::hasNext()
{
if (m_iPosition < COUNT)
{
return true;
}
else
{
return false;
}
}
int CAggregateBIter::next()
{
int iData = m_iData[m_iPosition];
++m_iPosition;
return iData;
}
CAggregateA::CAggregateA()
{
for (int i=0; i<COUNT; ++i)
{
m_vData.push_back(i*(i+1));
}
}
Iterator* CAggregateA::createIterator()
{
return new CAggregateAIter(m_vData);
}
CAggregateB::CAggregateB()
{
for (int i = 0; i < COUNT; ++i)
{
m_iData[i] = i*(i+1);
}
}
Iterator* CAggregateB::createIterator()
{
return new CAggregateBIter(m_iData);
}
void AggregateMg::printAggr()
{
Iterator* piter1 = m_aggrA.createIterator();
Iterator* piter2 = m_aggrB.createIterator();
printAggr(piter1);
printAggr(piter2);
delete piter1;
delete piter2;
}
void AggregateMg::printAggr(Iterator* piter)
{
while(piter->hasNext())
{
printf("%d\n",piter->next());
}
}
int main()
{
AggregateMg aggrMg;
aggrMg.printAggr();
return 0;
}
The running result is as follows:
0
2
6
12
20
0
2
6
12
20
Explanation:
1. When we use C ++ STL, the commonly used iterator methods include begin () and end. Some iterators provide methods such as first (), isdone (), and currentitem (). In fact, how to encapsulate them is the final implementation of the internal representation of the aggregation not exposed in the definition of the iterator mode, let the iterator implement the function of sequential access to elements in aggregation. We can even encapsulate some methods for operating aggregate elements for the iterator, such as remove ().
2. we decouple the aggregation management class from each aggregation class. If we add some other aggregation classes to the aggregation management class, therefore, we only need to modify a small amount of code to complete our work without affecting other functions.
Reference books: head first design model