美文网首页
S21. 迭代器模式

S21. 迭代器模式

作者: 拂去尘世尘 | 来源:发表于2022-05-04 14:46 被阅读0次

    迭代器模式

    提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。

    C++ STL中各个容器都有迭代器的体现,通过迭代器能够顺序的访问该容器各成员。

    意义

    有利于隐藏聚合类的内部实现,外部通过迭代器来实现对聚合类的顺序访问。

    场景

    实现聚合类的一种顺序访问。

    注: 对于开发者来讲,基本上不会实现一套迭代器。因为现存的标准库都有提供各种容器List、Array等,都有提供迭代器遍历。这里只是简单分析这种模式的实现原理。

    类图

    迭代器模式-类图.png
    • CIteratorBase: 迭代器基类。定义访问容器常用操作的接口。
    • CIterator: 具体迭代器类。负责实现访问容器常用操作的接口。
    • CAggregateBase: 聚合基类。表示具体的容器基类。
    • CAggregate: 具体聚合类。

    注: 为了实现通用的迭代器,迭代器类使用了泛型编程的模板方法。

    源码实现

    编程环境

    1. 编译环境: Linux环境
    2. 语言: C++语言
    3. 编译命令: make

    工程结构

    Iterator/
    ├── aggregatebase.h
    ├── aggregate.h
    ├── iteratorbase.h
    ├── iterator.h
    ├── main.cc
    └── Makefile
    
    • iterator*: 迭代器实现代码
    • aggregate*: 聚合类实现代码
    • main.cc: 客户端代码,程序入口
    • Makefile: 编译工具

    迭代器实现

    template<typename T>
    class CIterator : public CIteratorBase <T>
    {
    public:
        CIterator(CAggregate<T>* aggregate) : mIndex(0), mAgg(aggregate)
        {
    
        }
    
        ~CIterator()
        {
            if (NULL != mAgg) {
                delete mAgg;
            }
        }
    
        T* First()
        {
            mIndex = 0;
            if (mAgg->mData[0]) {
                return &mAgg->mData[0];
            } else {
                ITER_LOGE("mAgg is NULL!\n");
                return NULL;
            }
        }
    
        T* Next()
        {
            mIndex++;
            if (mIndex < mAgg->mData.size()) {
                return &mAgg->mData[mIndex];
            } else {
                ITER_LOGD("mAgg is NULL!\n");
                return NULL;
            }
        }
    
        T *CurPos()
        {
            if (mAgg->mData[mIndex]) {
                return &mAgg->mData[mIndex];
            } else {
                ITER_LOGE("mAgg is NULL!\n");
                return NULL;
            }
        }
    
        bool IsEnd()
        {
            if (mIndex < mAgg->mData.size()) {
                return true;
            } else {
                ITER_LOGD("mIndex[%d] Size[%ld]\n", mIndex, mAgg->mData.size());
                return false;
            }
        }
    
    private:
        unsigned int mIndex;
        CAggregate<T> *mAgg;
    };
    
    • 这里使用了泛型编程模板方式,适配各种类型聚合类的顺序访问。
    • 由于模板方式声明与实现不能分离,这里将两者都放在头文件,不利于实现的隐藏且不美观。如有更好的方式,可以后台告知,谢谢。

    聚合类实现

    template <typename T>
    class CAggregate : public CAggregateBase<T>
    {
        friend class CIterator <T>;
    
    public:
        CAggregate() : mIterator(NULL)
        {
    
        }
    
        ~CAggregate()
        {
            if (mIterator) {
                delete mIterator;
            }
        }
    
        void push_back(T data)
        {
            mData.push_back(data);
        }
    
    private:
        std::vector<T> mData;
        CIteratorBase<T>* mIterator;
    };
    
    • 同样的聚合类为了适配各类型,同样采用了泛型编程的模板方式。可把此类看成类似STL中的vector、List的容器类。其内部可存储同一类型的多个元素。
    • 此容器持有一个迭代器成员,外部可以通过此迭代器来访问容器中的各个元素。
    • 由于本设计迭代器需要访问聚合类私有的成员,因此将CIterator定义为友元,为了避免重复引用,前置声明CIterator。

    客户端代码
    测试内容大致为: 定义了一个容器,依次向容器中存放变量,并遍历。

    1. int型容器
    int main(int argc, char *argv[])
    {
        int i = 0;
        CAggregate<int> *agg = new CAggregate<int>();
        CIterator<int> it(agg);
    
        agg->push_back(1);
        agg->push_back(2);
        agg->push_back(13);
    
        for (it.First(); it.IsEnd(); it.Next())
        {
            printf("[%d]: %d\n", i, *it.CurPos());
            i++;
        }
    
        return 0;
    }
    
    1. float容器
    int main(int argc, char *argv[])
    {
        int i = 0;
        CAggregate<float> *agg = new CAggregate<float>();
        CIterator<float> it(agg);
    
        agg->push_back(1.2);
        agg->push_back(2);
        agg->push_back(13);
    
        for (it.First(); it.IsEnd(); it.Next())
        {
            printf("[%d]: %0.2f\n", i, *it.CurPos());
            i++;
        }
    
        return 0;
    }
    

    测试效果

    1. int型:
    $ ./exe 
    [0]: 1
    [1]: 2
    [2]: 13
    

    2: float型:

    ./exe 
    [0]: 1.20
    [1]: 2.00
    [2]: 13.00
    

    通过测试发现,两种类型的容器都可以实现遍历。

    总结

    • 单一职责原则。 通过将体积庞大的遍历算法代码抽取为独立的类, 你可对客户端代码和集合进行整理。
    • 开闭原则。 可以实现新型的集合和迭代器并将其传递给现有代码, 无需修改现有代码。
    • 可以并行遍历同一集合, 因为每个迭代器对象都包含其自身的遍历状态。
    • 在C++ STL库中已经提供迭代器的实现。本文的实现主要是了解迭代器的大致原理。

    相关文章

      网友评论

          本文标题:S21. 迭代器模式

          本文链接:https://www.haomeiwen.com/subject/xinwyrtx.html