设计模式----迭代器模式

发布于:2024-11-29 ⋅ 阅读:(16) ⋅ 点赞:(0)

定义

迭代器模式(Iterator Pattern)是一种行为设计模式。在 C++ 中,它提供了一种方法来顺序访问一个聚合对象(如容器,像vector、list等)中的各个元素,而又不暴露该对象的内部表示。简单来说,迭代器就像是一个导游,它可以带领你逐个访问容器中的元素,而不需要你了解容器是如何存储这些元素的。

组成部分

  • 迭代器(Iterator)接口:
    定义了访问和遍历元素的操作,通常包括first()(指向第一个元素)、next()(指向下一个元素)、isDone()(判断是否已经遍历完所有元素)和currentItem()(获取当前元素)等操作。在 C++ 中,标准库中的迭代器概念有输入迭代器、输出迭代器、前向迭代器、双向迭代器和随机访问迭代器,它们分别支持不同层次的操作。例如,输入迭代器支持++(向前移动)和*(解引用)操作,而随机访问迭代器还支持像[](下标访问)等更复杂的操作。
  • 具体迭代器(Concrete Iterator):
    实现了迭代器接口,它知道如何遍历一个聚合对象中的元素。例如,std::vector的迭代器是一个随机访问迭代器,它在内部记录了当前指向的元素位置,通过重载++运算符来移动到下一个元素,通过*运算符来返回当前元素的引用。
  • 聚合对象(Aggregate)接口:
    它是一个抽象接口,用于创建迭代器对象。在 C++ 中,容器类(如vector、list等)就相当于聚合对象,它们提供了像begin()和end()这样的成员函数来返回迭代器,这些迭代器用于遍历容器中的元素。
  • 具体聚合对象(Concrete Aggregate):
    实现了聚合对象接口,它包含了一个具体的容器和创建相应迭代器的方法。例如,std::vector是一个具体聚合对象,它内部存储了一个动态数组,并且可以通过begin()和end()函数返回用于遍历这个数组的迭代器。
  • 示例代码
    下面是一个简单的自定义迭代器和聚合对象的示例。假设我们有一个简单的数组类作为聚合对象:
class MyArray {
private:
    int* data;
    int size;
public:
    MyArray(int* arr, int n) : data(arr), size(n) {}
    class Iterator {
    private:
        int* current;
    public:
        Iterator(int* p) : current(p) {}
        int& operator*() {
            return *current;
        }
        Iterator& operator++() {
            current++;
            return *this;
        }
        bool operator!=(const Iterator& other) {
            return current!= other.current;
        }
    };
    Iterator begin() {
        return Iterator(data);
    }
    Iterator end() {
        return Iterator(data + size);
    }
};

可以这样使用这个自定义的迭代器和聚合对象:

int main() {
    int arr[] = {1, 2, 3, 4, 5};
    MyArray myArr(arr, 5);
    for (MyArray::Iterator it = myArr.begin(); it!= myArr.end(); ++it) {
        std::cout << *it << " ";
    }
    return 0;
}

在这个示例中,MyArray是聚合对象,它包含了一个整数数组。MyArray::Iterator是迭代器,它实现了*(解引用)、++(向前移动)和!=(比较)等操作。begin()和end()函数分别返回指向数组开头和结尾(后一个位置)的迭代器,这样就可以在for循环中使用迭代器来遍历数组中的元素了。

优势

  • 分离了聚合对象的遍历行为和内部结构:
    使得容器的实现可以独立于遍历操作,便于容器的维护和扩展。例如,vector和list的内部存储结构不同,但它们都可以提供统一的迭代器接口来进行元素遍历。
  • 提供了统一的遍历方式:
    对于不同类型的容器,用户可以使用相似的迭代器语法来遍历元素。例如,在 C++ 标准库中,vector、list和deque等容器都支持迭代器,用户可以使用begin()和end()函数获取迭代器,并通过for循环(如for(auto it = container.begin(); it!= container.end(); ++it))来遍历元素,而不需要了解每个容器的具体存储细节。
  • 支持多种遍历策略:
    可以通过定义不同的迭代器来实现不同的遍历策略。例如,除了正向遍历,还可以实现反向遍历的迭代器,或者实现跳过某些元素的迭代器等。

应用场景

  • 容器类的遍历:
    这是最常见的应用场景,如 C++ 标准库中的各种容器(vector、list、map等)都使用迭代器来提供元素遍历功能。在遍历容器时,用户可以使用迭代器来访问容器中的每个元素,而不需要关心容器的内部实现细节。
  • 数据结构的遍历:
    对于自定义的数据结构,如树、图等,也可以使用迭代器模式来提供遍历功能。例如,可以定义一个二叉树的中序遍历迭代器,它可以按照中序遍历的顺序逐个返回二叉树中的节点。
  • 数据库查询结果的遍历:
    在数据库编程中,查询结果通常是一个集合。可以使用迭代器来遍历这个集合,每次返回一条记录,方便对查询结果进行处理。