文章目录
- 一、引言
- 二、迭代器模式
- 三、总结
一、引言
迭代器模式是一种行为设计模式, 让你能在不暴露集合底层表现形式 (列表、 栈和树等) 的情况下遍历集合中所有的元素。C++标准库中内置了很多容器并提供了合适的迭代器,尽管我们不需要实现迭代器,但是需要了解迭代器的设计理念。
二、迭代器模式
我们设计一个固定大小数组作为容器,并实现一个迭代器。首先创建一个抽象迭代器:
template<class T>
class myIter{
public:
virtual void First() = 0;
virtual void Next() = 0;//指向下一个元素
virtual bool IsDone() = 0;//是否遍历完
virtual T& CurrentItem() = 0;//获取当前的元素
virtual ~myIter() {}//作父类时析构函数应该为虚函数
};
上述迭代器仅有四个接口,这4个接口一般被认为是选代器应该实现的最小接口。当然,也可以根据实际需要,增加更多的接口。接着,创建一个抽象容器:
template<class T>
class myContainer{
public:
public:
virtual myIter<T>* CreateIterator() = 0;//创建选代器
virtual T& getItem(int index) = 0;//获取当前元素
virtual int getSize() = 0;//容器中元素数量
virtual ~myContainer() {}//作父类时析构函数应该为虚函数
};
从上面的代码中可以看到,为了支持所谓的多态迭代,在抽象容器类模板中定义了一个CreateIterator
接口(成员函数),后续在具体的容器子类模板中,会在该接口中运用工厂模式创建相应的选代器。
template<class T>
class myVectorIter :public myIter<T>
{
public:
myVectorIter(myContainer<T>*tmpc) :myvector(tmpc)
{
m_current = 0;
}
virtual void First()
{
m_current = 0;//容器(数组)中的第一个元素下标为0
}
virtual void Next()
{
m_current++;//下标+1,意味着数组中的下一个元素
}
virtual bool IsDone()
{
if (m_current >= myvector->getSize())
return true;
return false;
}
virtual T& CurrentItem()
{
return myvector->getItem(m_current);
}
private:
myContainer<T>* myvector;
int m_current;//记录数组的当前下标(选代器在当前容器中的位置)
};
最后来一个具体的容器:
//具体容器类模板
template<typename T>
class myVector :public myContainer<T>{
public:
myVector()//将数组中元素进行初始化
{
for (int i = 0; i < 10; ++i)
m_elem[i] = i;
}
virtual myIter<T>* CreateIterator()
{
return new myVectorIter<T>(this);//要考虑在哪里释放的问题
}
virtual T& getItem(int index)
{
return m_elem[index];
}
virtual int getSize()
{
return 10;//为简化代码,返回固定数字
}
private:
//为了简化代码,将容器实现为固定装人10个元素的数组
T m_elem[10];
};
在上述代码中,CreateIterator
接口使用了工厂模式来创建一个具体的选代器,从而实现了多态选代(这意味着可以增加创建其他选代器的接口来支持不同的送代器,例如,再支持一个反向选代器来从最后一个元素向前遍历等)。
myContainer<int>* pcon = new myVector<int>();
myIter<int>* iter = pcon->CreateIterator();
for (iter->First(); !iter->IsDone(); iter->Next())
{
cout << iter->CurrentItem() << endl;
}
代码可以看到,我们的迭代器完成了对容器的遍历。
迭代器模式一般包含四个角色:
- 抽象迭代器(Iterator):用于定义访问和遍历容器中的元素接口。
- 具体迭代器(ConcreteIterator):实现了抽象迭代器的接口,完成对聚合对象的元素遍历,记录当前元素的位置。
- 抽象聚合(Aggregate):将聚合理解为容器,用于存储和管理元素对象,声明一个CreateIterator方法用于创建一个迭代器对象,充当创建迭代器的工厂角色
- 具体聚合(ConcreteAggregate):实现了抽象的
CreateIterator
方法以创建相应的迭代器,该方法返回ConcreteAggregate
的一个是适当的实例。
迭代器模式结构
迭代器模式做到了在不暴露内部结构的情况下,让外部代码透明地遍历(访问)其中包含元素的效果,另外值得一提的是,虽然不同的容器内部实现方式不同,但是通过迭代器来访问它们的方式却相同。
引入迭代器设计模式的定义:提供一种方法顺序访问一个聚合对象(容器)中各个元素,而又不暴露该对象的内部表示。
迭代器模式的核心思想就是把容器中对元素访问的代码放人迭代器中实现,与容器本身的功能代码相分离(容器是一个对象,迭代器是另一个对象),从而简化容器的设计。容器和迭代器之间彼此独立,从而使整个系统的设计更加灵活,可以定义不同的迭代器实现不同的遍历策略,例如常规迭代器、反向迭代器、const迭代器等都可以分别实现。
三、总结
当集合背后为复杂的数据结构, 且你希望对客户端隐藏其复杂性时 (出于使用便利性或安全性的考虑), 可以使用迭代器模式。迭代器封装了与复杂数据结构进行交互的细节, 为客户端提供多个访问集合元素的简单方法。 这种方式不仅对客户端来说非常方便, 而且能避免客户端在直接与集合交互时执行错误或有害的操作, 从而起到保护集合的作用。
使用方法:
- 声明迭代器接口。 该接口必须提供至少一个方法来获取集合中的下个元素。 但为了使用方便, 你还可以添加一些其他方法, 例如获取前一个元素、 记录当前位置和判断迭代是否已结束。
- 声明集合接口并描述一个获取迭代器的方法。 其返回值必须是迭代器接口。 如果你计划拥有多组不同的迭代器, 则可以声明多个类似的方法。
- 为希望使用迭代器进行遍历的集合实现具体迭代器类。 迭代器对象必须与单个集合实体链接。 链接关系通常通过迭代器的构造函数建立。
- 在你的集合类中实现集合接口。 其主要思想是针对特定集合为客户端代码提供创建迭代器的快捷方式。 集合对象必须将自身传递给迭代器的构造函数来创建两者之间的链接。
- 检查客户端代码, 使用迭代器替代所有集合遍历代码。 每当客户端需要遍历集合元素时都会获取一个新的迭代器。
我们可以使用迭代器模式来遍历组合模式。也可以使用工厂方法模式和迭代器来让子类返回不同的迭代器,并使得迭代器与集合相匹配。
身传递给迭代器的构造函数来创建两者之间的链接。
5. 检查客户端代码, 使用迭代器替代所有集合遍历代码。 每当客户端需要遍历集合元素时都会获取一个新的迭代器。
我们可以使用迭代器模式来遍历组合模式。也可以使用工厂方法模式和迭代器来让子类返回不同的迭代器,并使得迭代器与集合相匹配。