设计模式之迭代器模式

迭代器模式(Iterator Pattern)是一种行为设计模式,它提供了一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。迭代器模式使得不同的聚合结构可以使用统一的接口来遍历其元素。

使用场景

  1. 遍历集合对象
    当你需要遍历一个集合对象中的所有元素时,可以使用迭代器模式。

    示例:在一个列表、栈、队列等集合中,使用迭代器模式来遍历元素。

  2. 提供统一的遍历接口
    当你希望不同的集合结构提供统一的遍历接口时,可以使用迭代器模式。

    示例:不同的容器类型(如数组和链表)可以使用相同的迭代器接口来遍历其元素。

  3. 隐藏集合的内部实现
    当你希望隐藏集合的内部实现,只暴露一个遍历接口时,可以使用迭代器模式。

    示例:在一个图书馆管理系统中,用户可以遍历图书集合,但不需要知道图书集合的具体实现。

UML类图

+-------------------+       +-------------------+
|  Iterator         |       | Aggregate         |
+-------------------+       +-------------------+
| +first()          |       | +createIterator() |
| +next()           |       +-------------------+
| +isDone()         |               /|\
| +currentItem()    |                |
+-------------------+                |
          ^                          |
          |                          |
+-------------------+       +-------------------+
| ConcreteIterator  |       | ConcreteAggregate |
+-------------------+       +-------------------+
| -current: int     |       | -items: List      |
| +first()          |       | +createIterator() |
| +next()           |       +-------------------+
| +isDone()         |
| +currentItem()    |
+-------------------+

类图解释

  1. Iterator(迭代器接口)

    • 职责:定义访问和遍历元素的接口方法。
    • 方法
      • first():将迭代器定位到第一个元素。
      • next():将迭代器移动到下一个元素。
      • isDone():检查是否遍历完所有元素。
      • currentItem():返回当前元素。
  2. ConcreteIterator(具体迭代器)

    • 职责:实现迭代器接口,维护当前遍历位置。
    • 属性
      • current:当前元素的索引。
    • 方法
      • 实现 Iterator 接口的所有方法,管理遍历的状态和行为。
  3. Aggregate(聚合接口)

    • 职责:定义创建迭代器的接口方法。
    • 方法
      • createIterator():创建并返回一个迭代器对象。
  4. ConcreteAggregate(具体聚合)

    • 职责:实现聚合接口,存储集合元素并返回具体的迭代器对象。
    • 属性
      • items:存储集合元素的列表。
    • 方法
      • 实现 Aggregate 接口的 createIterator 方法,返回一个具体的迭代器对象。

示例代码

假设我们有一个集合类,用于存储整数,并提供遍历这些整数的方法。我们用迭代器模式来实现这个场景。

#include <iostream>
#include <vector>
#include <memory>

// 迭代器接口
template <typename T>
class Iterator {
public:
    virtual void first() = 0;
    virtual void next() = 0;
    virtual bool isDone() const = 0;
    virtual T currentItem() const = 0;
    virtual ~Iterator() = default;
};

// 聚合接口
template <typename T>
class Aggregate {
public:
    virtual std::unique_ptr<Iterator<T>> createIterator() const = 0;
    virtual ~Aggregate() = default;
};

// 具体迭代器
template <typename T>
class ConcreteIterator : public Iterator<T> {
public:
    ConcreteIterator(const std::vector<T>& items)
        : items_(items), current_(0) {}

    void first() override {
        current_ = 0;
    }

    void next() override {
        if (!isDone()) {
            ++current_;
        }
    }

    bool isDone() const override {
        return current_ >= items_.size();
    }

    T currentItem() const override {
        if (!isDone()) {
            return items_[current_];
        }
        throw std::out_of_range("Iterator out of range");
    }

private:
    const std::vector<T>& items_;
    size_t current_;
};

// 具体聚合
template <typename T>
class ConcreteAggregate : public Aggregate<T> {
public:
    ConcreteAggregate(const std::initializer_list<T>& items)
        : items_(items) {}

    std::unique_ptr<Iterator<T>> createIterator() const override {
        return std::make_unique<ConcreteIterator<T>>(items_);
    }

private:
    std::vector<T> items_;
};

// 客户端代码
int main() {
    ConcreteAggregate<int> aggregate = {1, 2, 3, 4, 5};
    std::unique_ptr<Iterator<int>> iterator = aggregate.createIterator();

    for (iterator->first(); !iterator->isDone(); iterator->next()) {
        std::cout << iterator->currentItem() << " ";
    }

    std::cout << std::endl;
    return 0;
}

代码解读

  1. Iterator(迭代器接口)

    • 职责:定义了访问和遍历集合元素的方法。
    • 方法
      • first():将迭代器定位到第一个元素。
      • next():将迭代器移动到下一个元素。
      • isDone():检查是否遍历完所有元素。
      • currentItem():返回当前元素。
  2. ConcreteIterator(具体迭代器)

    • 职责:实现 Iterator 接口,维护当前遍历位置。
    • 属性
      • items_:存储集合元素的引用。
      • current_:当前元素的索引。
    • 方法
      • 实现 Iterator 接口的所有方法,管理遍历的状态和行为。
  3. Aggregate(聚合接口)

    • 职责:定义创建迭代器的接口方法。
    • 方法
      • createIterator():创建并返回一个迭代器对象。
  4. ConcreteAggregate(具体聚合)

    • 职责:实现 Aggregate 接口,存储集合元素并返回具体的迭代器对象。
    • 属性
      • items_:存储集合元素的列表。
    • 方法
      • 实现 Aggregate 接口的 createIterator 方法,返回一个具体的迭代器对象。

优点

  1. 统一遍历接口
    通过迭代器模式,不同的集合结构可以使用相同的接口来遍历其元素。

  2. 隐藏集合的内部实现
    迭代器模式隐藏了集合的内部实现,只暴露了遍历元素的方法。

  3. 提高代码的灵活性
    迭代器模式使得集合和遍历算法可以独立变化,提高了代码的灵活性和可维护性。

缺点

  1. 增加了类的数量
    使用迭代器模式会增加额外的迭代器类和接口,增加了代码的复杂性。

  2. 可能影响性能
    迭代器的实现需要维护遍历状态,可能会带来一定的性能开销。

使用场景总结

  1. 遍历集合对象:如列表、栈、队列等集合。
  2. 提供统一的遍历接口:如不同容器类型使用相同的迭代器接口。
  3. 隐藏集合的内部实现:如图书馆管理系统中的图书集合。

通过这个例子和解释,可以看到迭代器模式在提供统一的遍历接口、隐藏集合内部实现和提高代码灵活性方面的强大功能。

示例2

图书馆书架

假设我们有一个图书馆,其中有多种类型的书架,每个书架存放不同类别的书。我们需要一个迭代器来遍历这些书架上的书,并且让这个迭代器模式适应不同类型的书架。

具体代码示例

我们将使用两个不同类型的书架,一个用于存放小说,另一个用于存放科学书籍。每个书架都有自己的迭代器来遍历其中的书籍。

#include <iostream>
#include <vector>
#include <memory>
#include <string>

// 迭代器接口
template <typename T>
class Iterator {
public:
    virtual void first() = 0;
    virtual void next() = 0;
    virtual bool isDone() const = 0;
    virtual T currentItem() const = 0;
    virtual ~Iterator() = default;
};

// 聚合接口
template <typename T>
class Aggregate {
public:
    virtual std::unique_ptr<Iterator<T>> createIterator() const = 0;
    virtual ~Aggregate() = default;
};

// 小说书架迭代器
class NovelIterator : public Iterator<std::string> {
public:
    NovelIterator(const std::vector<std::string>& books)
        : books_(books), current_(0) {}

    void first() override {
        current_ = 0;
    }

    void next() override {
        if (!isDone()) {
            ++current_;
        }
    }

    bool isDone() const override {
        return current_ >= books_.size();
    }

    std::string currentItem() const override {
        if (!isDone()) {
            return books_[current_];
        }
        throw std::out_of_range("Iterator out of range");
    }

private:
    const std::vector<std::string>& books_;
    size_t current_;
};

// 科学书架迭代器
class ScienceIterator : public Iterator<std::string> {
public:
    ScienceIterator(const std::vector<std::string>& books)
        : books_(books), current_(0) {}

    void first() override {
        current_ = 0;
    }

    void next() override {
        if (!isDone()) {
            ++current_;
        }
    }

    bool isDone() const override {
        return current_ >= books_.size();
    }

    std::string currentItem() const override {
        if (!isDone()) {
            return books_[current_];
        }
        throw std::out_of_range("Iterator out of range");
    }

private:
    const std::vector<std::string>& books_;
    size_t current_;
};

// 小说书架
class NovelShelf : public Aggregate<std::string> {
public:
    NovelShelf(const std::initializer_list<std::string>& books)
        : books_(books) {}

    std::unique_ptr<Iterator<std::string>> createIterator() const override {
        return std::make_unique<NovelIterator>(books_);
    }

private:
    std::vector<std::string> books_;
};

// 科学书架
class ScienceShelf : public Aggregate<std::string> {
public:
    ScienceShelf(const std::initializer_list<std::string>& books)
        : books_(books) {}

    std::unique_ptr<Iterator<std::string>> createIterator() const override {
        return std::make_unique<ScienceIterator>(books_);
    }

private:
    std::vector<std::string> books_;
};

// 客户端代码
int main() {
    NovelShelf novelShelf = {"The Great Gatsby", "To Kill a Mockingbird", "1984"};
    ScienceShelf scienceShelf = {"A Brief History of Time", "The Selfish Gene", "Cosmos"};

    std::unique_ptr<Iterator<std::string>> novelIterator = novelShelf.createIterator();
    std::unique_ptr<Iterator<std::string>> scienceIterator = scienceShelf.createIterator();

    std::cout << "Novels:" << std::endl;
    for (novelIterator->first(); !novelIterator->isDone(); novelIterator->next()) {
        std::cout << novelIterator->currentItem() << std::endl;
    }

    std::cout << "\nScience Books:" << std::endl;
    for (scienceIterator->first(); !scienceIterator->isDone(); scienceIterator->next()) {
        std::cout << scienceIterator->currentItem() << std::endl;
    }

    return 0;
}

工作流程

  1. 创建具体集合对象

    • 创建具体的集合对象,如 NovelShelfScienceShelf,并初始化其中的元素。
  2. 创建迭代器对象

    • 调用具体集合对象的 createIterator 方法,创建并返回一个具体的迭代器对象。
  3. 遍历集合元素

    • 使用迭代器对象的 firstnextisDonecurrentItem 方法,遍历集合中的元素。

通过这个独特的例子,可以看到迭代器模式如何在不同类型的书架中应用,并且统一了遍历接口,使得客户端代码可以以相同的方式遍历不同的集合。

下面我来做一个总结吧!

总的来说,迭代器模式的核心就是提供一种统一的方式来遍历不同类型的集合。无论集合的内部实现是数组、链表、树还是其他数据结构,迭代器模式都可以提供一致的遍历接口,让客户端代码无需关心集合的具体实现细节

关键点总结

  1. 统一遍历接口
    迭代器模式为不同类型的集合提供了统一的遍历接口,使得客户端代码可以用相同的方式遍历不同的集合。

  2. 隐藏内部实现
    迭代器模式隐藏了集合的内部实现细节,只暴露遍历所需的接口,减少了客户端代码对集合具体实现的依赖。

  3. 增加代码灵活性和可维护性
    通过统一的遍历接口,迭代器模式提高了代码的灵活性和可维护性,使得集合和遍历算法可以独立变化。

示例中的体现

在我们的示例中,NovelShelfScienceShelf 分别表示不同类型的书架,每个书架都有自己的具体迭代器 NovelIteratorScienceIterator。通过实现统一的 Iterator 接口,这些迭代器提供了一致的遍历方法(first, next, isDone, currentItem),使得客户端代码可以用相同的方式遍历这两种不同的书架。

适用场景

迭代器模式在以下场景中特别有用:

  1. 多种集合类型
    当系统中存在多种不同类型的集合(如数组、链表、树等)时,迭代器模式可以提供一致的遍历接口,简化客户端代码。

  2. 需要隐藏集合实现
    当需要隐藏集合的内部实现,只暴露遍历接口时,迭代器模式是一个很好的选择。

  3. 需要频繁遍历集合
    当系统需要频繁遍历集合中的元素时,迭代器模式可以提高代码的灵活性和可维护性。

结论

迭代器模式提供了一种统一的方式来遍历不同类型的集合,使得客户端代码可以用一致的方式遍历这些集合,增强了代码的灵活性和可维护性。随着集合类型的增多,这种统一遍历的优势会更加明显。

希望这样的解释可以帮到你!!!

  • 22
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值