C++ Iterator设计模式学习

166 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

原文链接:blog.csdn.net/roufoo/arti…

Iterator设计模式是GOF里面的23中设计模式之一, 其定义是”提供一种方法访问一个容器对象中各个元素,而又不暴露该对象的内部细节。”

在没有学Iterator设计模式之前,如果要遍历容器里面的各个元素,我们可能想到的就是用一个链表把这些元素连起来,然后通过->next来遍历这些元素。但是这样就暴露了容器的内部细节。另外,如果有多个client同时遍历这个容器,可能还要给这个链表加个锁什么的,这样又浪费了系统资源。这些问题的原因都是容器的内部和它的遍历紧耦合了。

Iterator设计模式则把容器的内部实现和它的遍历实现了解耦,其结构图如下:

image.png

上面的各个部分说明如下: Iterator:定义迭代器访问和遍历元素的接口; ConcreteIterator:实现具体的迭代器; Aggregate:定义的容器,创建相应迭代器对象的接口; ConcreteAggregate:具体的容器实现创建相应迭代器的接口,该操作返回ConcreteIterator的一个适当的实例。

一个Iterator设计模式的基本代码如下:

template<typename T>
class Iterator
{
public:
    virtual void first() = 0;
    virtual void next() = 0;
    virtual bool isDone() const = 0;
    virtual T& current() = 0;
};

![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ffe216a38dfd4d0397a20c0a86486527~tplv-k3u1fbpfcp-watermark.image?)
template<typename T>
class MyCollection{

public:

    Iterator<T> GetIterator(){
        //...
    }

};

template<typename T>
class CollectionIterator : public Iterator<T>{
    MyCollection<T> mc;
public:

    CollectionIterator(const MyCollection<T> & c): mc(c){ }

    void first() override {

    }
    void next() override {

    }
    bool isDone() const override{

    }
    T& current() override{

    }
};

void MyAlgorithm()
{
    MyCollection<int> mc;

    Iterator<int> iter= mc.GetIterator();

    for (iter.first(); !iter.isDone(); iter.next()){
        cout << iter.current() << endl;
    }

}

在上面代码中,CollectionIterator就是结构图里面的ConcreteAggregate,里面包含了MyCollection的对象mc。在for loop中,里面的first(),isDone()和next()都是重载后的虚函数,实现运行时绑定。这样,用户并不知道MyCollection的内部细节,也可以实现遍历。

不过我想补充的是Iterator这种设计模式在JAVA里面用的很多,但是在C++里面已经过时了。为什么呢?因为Iterator设计模式是基于虚函数的,属于运行时绑定。我们知道虚函数运行时绑定就要查虚函数表,如果在一个很大的loop里面的话,这种虚函数绑定累计起来就耽误了很多时间,效率非常低。

而C++的STL是采用泛型编程,属于编译时绑定,效率非常高。那么为什么泛型编程可以在编译时绑定呢?因为它是基于Traits实现的,内部用到了类模板和偏特化。所以STL里面的Iterator并不是用的Iterator设计模式!