【设计模式攻略】行为型模式之Iterator模式

本文介绍迭代器模式的核心概念,探讨其在C++中的实现方法,包括如何为不同的容器设计迭代器,以及如何在容器类中提供创建迭代器的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概要
程序中最常见的一种数据形式之一,就是集合。集合就是vector,list,set,map等容器的统称。使用容器都有一个常规的问题,就是对容器内数据的访问,包括查询,遍历等等操作。而要实现这些操作,普遍的做法就是通过迭代器来实现。很多人在封装自定义的某种集合的数据类型时,往往会在集合类型中额外增加遍历,查询的接口,但这种做法其实并不属于迭代器的范畴。常规的迭代器应该具备如下特点:
1. 通过迭代器来访问数据集合的内容,而不需要暴露数据集合本身的内部类型
2. 支持多线同时对同一集合的遍历,互不影响
3. 提供统一的接口来实现各种集合内数据的访问

目的
提供一种访问内聚集合中各个成员的方法,而不需要暴露集合成员本身的数据类型。

实例
迭代器的实现方式有很多,而且基于不同语言的语法特性,不同语言的实现方式也有所不同,JDK中对各类Collection的迭代器的实现,C++ STL中对各类容器的迭代器的实现等等都是其中的经典。当然,不管实现方式如何,目的都是一致的。为了说明迭代器模式本身,我们也来看一下C++的一种最基本的实现方式。
假设我们迭代器的接口类为IIterator, 包含迭代器的常规方法,如下:
template <typename Type>
class IIterator {
public :
    virtual void first() = 0;
    virtual void next() = 0;
    virtual bool is_available() const = 0 ;
    virtual Type current_item() const = 0;
};
由于C++不存在根对象(类似Jave中的Object),所以通过模板来通用化的实现。有了接口类,我们就可以为所需要的类型实现对应的迭代器,比如如果需要vector的迭代器,则可以如下来实现:
template<typename Type>
class VecIterator : public IIterator<Type> {
public:
      VecIterator( const std::vector<Type>* vec) : m_current(0), m_vec(vec) {}
       virtual void first() {
            m_current = 0;
      }
       virtual void next() {
            m_current++;
      }
       virtual bool is_available() const {
             return (m_current < m_vec->size());
      }
       virtual Type current_item() const {
             if (!this ->is_available()) {
                   throw;
            }
             return (*m_vec)[m_current];
      }

private:
       long m_current;
       const std::vector<Type>* m_vec;
};
这里is_available方法是用来判断当前成员是否有效,索引越界则代表无效。同时如果我们要实现List的迭代器也是一样,从IIterator派生出ListIterator然后实现相关操作就ok了。

从上面实现代码可以看出,迭代器类的构造函数需要具体容器对象作为参数,也就是说迭代器对象本身都是依赖于具体容器对象的,所以一般而言不建议由用户如下来自己定义迭代器对象:
vector<int> ivec(10,1);
VecIterator< int>* it = new VecIterator<int>(&ivec);
而比较合理的是在容器类本身提供创建对应迭代器的方法,比如在vector类中通过create_iterator()方法来得到vector的迭代器:
template<typename Type>
class vector : public XXXX {
......
     VecIterator<Type> create_iterator() {
          return VecIterator<Type>(this);
     }
......
}
在实际代码中则可以如下使用:
vector< int> ivec(10,1);
VecIterator<int> it = ivec.create_iterator();
但是如果想让create_iterator称为容器接口类的抽象方法时,则根据依赖倒置原则,方法的定义应该依赖于抽象迭代器类型,而非具体容器的迭代器类型,与之所对应的,为了保证多态性,返回值需要是指针类型,如下所示:
Iterator<Type>* create_iterator() {
    return new VecIterator<Type>(this);
}
然而,这样又带来另外一个问题,因为C++不存在垃圾自动回收机制,那么如何保证迭代器对象被销毁呢?方法之一是额外封装迭代器指针包装类,类似最简化的不含引用计数的智能指针,具体实现这里就不多做说明了,相关资料比较多,特别需要的可以给我留言。唉,这也是C++比之Java之类的麻烦之处,一样的代码,需要反复斟酌才能较好的实现,其实敢兴趣的话可以参考下STL中各种iterator的实现,那才是艺术。

迭代器模式通常实现形式的类图表现如下:


应用
关于迭代器的应用,多说一个字都是废话,没用过的话确实不好意思说自己写过程序。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值