转载自:
http://patmusing.blog.163.com/blog/static/13583496020101501613155/
“Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.” – GoF
提供一种方法,以顺序访问一个聚合对象中的元素,而又不暴露该聚合对象之内部表示。
An aggregate object such as a list should give you a way to access its elements without exposing its internal structure. Moreover, you might want to traverse the list in different ways, depending on what you want to accomplish. But you probably don’t want to bloat the List interface with operations for different traversals, even if you could anticipate the ones you will need. You might also need to have more than one traversal pending on the same list.
The Iterator pattern lets you do all this. The key idea in this pattern is to take the responsibility for access and traversal out of the list object and put it into an iterator object. The Iterator class defines an interface for accessing the list’s elements. An iterator object is responsible for keeping track of the current element; that is, it knows which elements have been traversed already.
在软件构建过程中, 集合对象内部结构常常变化各异。但对于这些集合对象,我们希望在不暴露其内部结构的同时,可以让外部客户代码透明地访问其中包含的元素;同时这种“透明遍历”也为“同一种算法在多种结合对象上进行操作”提供了可能。使用面向对象技术,将这种遍历机制抽象为“迭代器对象”,为“应对变化中的集合对象”提供了一种优雅的遍历方式。
Iterator设计模式UML类图:
要点:
- 迭代抽象: 访问一个聚合对象的内容,而无需暴露其内部表示。
- 迭代多态: 为遍历不同的集合结构提供一个统一的接口,从而支持同样的算法在不同的集合结构上进行操作。
- 迭代器通常不应该修改所在集合的结构,如删除其中一个元素,也就是迭代器通常是只读的,但未必尽然。
下面是具体的C++实现代码:
// Iterator.h
#include <string>
#include <iostream>
#include <memory>
using namespace std;
// 这个类将作为集合中的元素
class Person
{
private:
string name;
string mobilephone;
public:
// 由于ConcreteCollection类的构造函数中的collection = new T[100];这一句,因此,Person类
// 必须提供缺省构造函数
Person()
{
}
Person(const string name, const string mobilephone)
{
this->name = name;
this->mobilephone = mobilephone;
}
~Person()
{
//由于Person类的析构函数会被调用很多次,所以就把下面一行注释了,以便使得输出更整洁一些
//cout << "in the destructor of Person..." << endl;
}
public:
// 显示元素本身的内容
string to_string()
{
string str = name + "\t" + mobilephone;
return str;
}
};
// 这是迭代器所必须实现的接口
template <typename T>
class IIterator
{
public:
virtual T next() = 0; // 取出下一个元素
virtual bool has_next() = 0; // 遍历完了吗?如果遍历完,则返回false;否则,返回true
public:
virtual ~IIterator()
{
cout << "in the destructor of IIterator..." << endl;
}
};
// 定义IIterable接口,所有的欲使用迭代器的集合类,都必须继承它
template <typename T>
class IIterable
{
public:
virtual auto_ptr<IIterator<T> > get_iterator() = 0; // 获取迭代器(智能指针)
public:
virtual ~IIterable()
{
cout << "in the destructor of IIterable..." << endl;
}
};
// 具体集合类
template <typename T>
class ConcreteCollection : public IIterable<T>
{
private:
int index;
T *collection;
public:
ConcreteCollection()
{
collection = new T[100];
index = 0;
}
// 增加一个元素
void add_element(T obj)
{
collection[index++] = obj;
}
// 获取一个指定位置的元素
T get_element_at(int i)
{
return collection[i];
}
// 获取集合中元素的个数
int get_size()
{
return index;
}
// 获取迭代器(智能指针)
auto_ptr<IIterator<T> > get_iterator()
{
auto_ptr<IIterator<T> > temp(new ConcreteIterator<Person>(this));
return temp;
}
public:
~ConcreteCollection()
{
delete [] collection; // 对应构造函数中的collection = new T[100];
cout << "in the destructor of ConcreteCollection..." << endl;
}
};
// 具体迭代器类
template <typename T>
class ConcreteIterator : public IIterator<T>
{
private:
int index;
ConcreteCollection<T> *collection;
public:
ConcreteIterator(IIterable<T> *iterable)
{
index = 0;
collection = dynamic_cast<ConcreteCollection<T> *>(iterable);
// 向下转型,即将基类的指针转换为派生类的指针,此处使用dynamic_cast
// 是为了进行严格的类型检查。一般而言,向下转型时不安全的,因此要使
// 用dynamic_cast
}
bool has_next()
{
if(0 == collection->get_size())
{
return false;
}
if(index < collection->get_size())
{
return true;
}
else
{
return false;
}
}
T next()
{
return collection->get_element_at(index++);
}
public:
~ConcreteIterator()
{
cout << "in the destructor of ConcreteIterator..." << endl;
}
};
// Iterator.cpp
#include "Iterator.h"
int main(int argc, char **argv)
{
ConcreteCollection<Person> *collection = new ConcreteCollection<Person>();
collection->add_element(Person("玄机逸士", "13800000001"));
collection->add_element(Person("上官天野", "13800000002"));
collection->add_element(Person("黄药师 ", "13800000003"));
collection->add_element(Person("欧阳锋 ", "13800000004"));
collection->add_element(Person("段王爷 ", "13800000005"));
collection->add_element(Person("洪七公 ", "13800000006"));
auto_ptr<IIterator<Person> > iter(collection->get_iterator());
while(iter->has_next())
{
cout << (iter->next()).to_string() << endl;
}
delete collection;
return 0;
}
运行结果:
玄机逸士 13800000001
上官天野 13800000002
黄药师 13800000003
欧阳锋 13800000004
段王爷 13800000005
洪七公 13800000006
in the destructor of ConcreteCollection...
in the destructor of IIterable...
in the destructor of ConcreteIterator...
in the destructor of IIterator...
与上述程序对应的UML类图:
Iterator模式实现需注意的要点:
1. 两个重要接口,即IIterable和IIterator,它们分别对应的具体类ConcreteCollection和ConcreteIterator。本质上而言ConcreteCollection中存放的是数据,ConcreteIterator中实现的是遍历的方法。
2. ConcreteCollection中的getIterator()方式的实现技巧。即
return new ConcreteIterator(this);
ConcreteCollection将自己(当然也包括ConcreteCollection中包含的数据)通过ConcreteIterator的构造函数,传递给ConcreteIterator,然后ConcreteIterator利用已实现的方法对其进行遍历。
3. 模板类的应用。上述实现由于使用了模板,因此ConcreteCollection中的元素也可以是除Person类之外的其他类型。