C++设计模式:迭代器模式(书籍管理系统)

什么是迭代器模式?

迭代器模式是一种行为型设计模式,它允许我们顺序地访问一个集合中的元素,而无需了解集合的内部结构

通俗解释
  • 迭代器模式就像一本书的书签,可以逐页翻阅内容,而不需要关心书的具体装订方式。
  • 比如:我们在遍历数组、链表或集合时,只需要迭代器提供的接口来访问数据,而无需知道数组或链表的实现细节。

迭代器模式的特点

  1. 解耦遍历逻辑和集合实现

    • 迭代器提供统一的接口,用户无需关心集合的内部结构(比如数组、链表等)。
  2. 提供多种遍历方式

    • 可以实现正序遍历、逆序遍历等不同方式。
  3. 统一集合的访问方式

    • 通过迭代器,可以用相同的方式访问不同类型的集合。

迭代器模式的结构

UML 类图
        +--------------------+
        |    Iterator        |  // 抽象迭代器接口
        +--------------------+
        |  + first()         |
        |  + next()          |
        |  + isDone()        |
        |  + currentItem()   |
        +--------------------+
                  ^
                  |
    +---------------------------+
    | ConcreteIterator          |  // 具体迭代器
    +---------------------------+
                  ^
                  |
        +--------------------+
        |    Aggregate       |  // 抽象集合
        +--------------------+
        |  + createIterator()|
        +--------------------+
                  ^
                  |
    +---------------------------+
    | ConcreteAggregate         |  // 具体集合
    +---------------------------+
组成部分
  1. Iterator(抽象迭代器)

    • 定义了访问集合元素的接口,例如first()next()isDone()currentItem()
  2. ConcreteIterator(具体迭代器)

    • 实现Iterator接口,负责遍历具体集合的元素。
  3. Aggregate(抽象集合)

    • 定义集合的接口,通常包含创建迭代器的方法createIterator()
  4. ConcreteAggregate(具体集合)

    • 实现Aggregate接口,存储数据,并提供方法创建迭代器。

迭代器模式的优点和缺点

优点
  1. 封装集合内部结构:使用迭代器可以隐藏集合的实现细节。
  2. 统一遍历接口:不同类型的集合可以通过相同的迭代器接口进行访问。
  3. 扩展性强:可以轻松增加新的迭代器类型(如逆序迭代器)。
缺点
  1. 类的数量增加:每种集合都需要一个具体的迭代器类。
  2. 额外的开销:迭代器的创建和维护会带来额外的性能开销。

案例:图书馆书籍集合遍历

需求描述
  • 我们需要设计一个图书馆的书籍管理系统,其中图书馆存储了一些书籍。
  • 用户可以通过迭代器来逐本访问这些书籍,而无需关心书籍存储的方式(例如是数组还是链表)。

代码实现

以下是完整的代码实现,输出信息为中文,并配有详细注释。

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

// 抽象迭代器接口
class Iterator {
public:
    virtual void first() = 0;                  // 将迭代器移动到第一个元素
    virtual void next() = 0;                   // 移动到下一个元素
    virtual bool isDone() const = 0;           // 检查是否已到达集合末尾
    virtual std::string currentItem() const = 0; // 获取当前元素
    virtual ~Iterator() = default;
};

// 抽象集合接口
class Aggregate {
public:
    virtual std::shared_ptr<Iterator> createIterator() = 0; // 创建迭代器
    virtual ~Aggregate() = default;
};

// 具体集合类:书籍集合
class BookCollection : public Aggregate {
private:
    std::vector<std::string> books; // 用于存储书籍的集合

public:
    // 添加书籍
    void addBook(const std::string& book) {
        books.push_back(book);
    }

    // 获取书籍总数
    size_t getSize() const {
        return books.size();
    }

    // 根据索引获取书籍
    std::string getBook(size_t index) const {
        if (index < books.size()) {
            return books[index];
        }
        return "";
    }

    // 实现创建迭代器的方法
    std::shared_ptr<Iterator> createIterator() override;

    // 声明迭代器为友元类,方便访问私有数据
    friend class BookIterator;
};

// 具体迭代器类:书籍迭代器
class BookIterator : public Iterator {
private:
    const BookCollection& collection; // 引用书籍集合
    size_t currentIndex;              // 当前迭代器位置

public:
    // 构造函数
    BookIterator(const BookCollection& collection) 
        : collection(collection), currentIndex(0) {}

    // 实现迭代器接口方法
    void first() override {
        currentIndex = 0; // 移动到第一个元素
    }

    void next() override {
        if (currentIndex < collection.getSize()) {
            ++currentIndex; // 移动到下一个元素
        }
    }

    bool isDone() const override {
        return currentIndex >= collection.getSize(); // 检查是否到达集合末尾
    }

    std::string currentItem() const override {
        if (!isDone()) {
            return collection.getBook(currentIndex); // 返回当前书籍
        }
        return "无效的书籍"; // 如果越界,返回无效
    }
};

// 在BookCollection中实现创建迭代器的方法
std::shared_ptr<Iterator> BookCollection::createIterator() {
    return std::make_shared<BookIterator>(*this);
}

// 客户端代码
int main() {
    // 创建一个书籍集合
    BookCollection library;
    library.addBook("C++编程入门");
    library.addBook("设计模式详解");
    library.addBook("数据结构与算法");
    library.addBook("操作系统原理");

    // 创建迭代器
    auto iterator = library.createIterator();

    // 使用迭代器访问集合中的元素
    std::cout << "图书馆中的书籍列表:" << std::endl;
    for (iterator->first(); !iterator->isDone(); iterator->next()) {
        std::cout << " - " << iterator->currentItem() << std::endl;
    }

    return 0;
}

运行结果

图书馆中的书籍列表:
 - C++编程入门
 - 设计模式详解
 - 数据结构与算法
 - 操作系统原理

代码讲解

1. 抽象迭代器接口(Iterator
class Iterator {
public:
    virtual void first() = 0;
    virtual void next() = 0;
    virtual bool isDone() const = 0;
    virtual std::string currentItem() const = 0;
    virtual ~Iterator() = default;
};
  • first():将迭代器移动到集合的第一个元素。
  • next():移动到下一个元素。
  • isDone():检查是否已经到达集合末尾。
  • currentItem():获取当前元素。
2. 抽象集合接口(Aggregate
class Aggregate {
public:
    virtual std::shared_ptr<Iterator> createIterator() = 0; // 创建迭代器
    virtual ~Aggregate() = default;
};
  • 定义了一个createIterator方法,用于创建迭代器。
3. 具体集合类(BookCollection
class BookCollection : public Aggregate {
private:
    std::vector<std::string> books;

public:
    void addBook(const std::string& book) {
        books.push_back(book);
    }

    size_t getSize() const {
        return books.size();
    }

    std::string getBook(size_t index) const {
        if (index < books.size()) {
            return books[index];
        }
        return "";
    }

    std::shared_ptr<Iterator> createIterator() override {
        return std::make_shared<BookIterator>(*this);
    }
};
  • books存储书籍集合。
  • 提供了添加书籍、获取书籍的方法。
  • createIterator方法返回一个BookIterator对象。
4. 具体迭代器类(BookIterator
class BookIterator : public Iterator {
private:
    const BookCollection& collection;
    size_t currentIndex;

public:
    BookIterator(const BookCollection& collection) 
        : collection(collection), currentIndex(0) {}

    void first() override {
        currentIndex = 0;
    }

    void next() override {
        if (currentIndex < collection.getSize()) {
            ++currentIndex;
        }
    }

    bool isDone() const override {
        return currentIndex >= collection.getSize();
    }

    std::string currentItem() const override {
        if (!isDone()) {
            return collection.getBook(currentIndex);
        }
        return "无效的书籍";
    }
};
  • 通过currentIndex记录当前访问位置。
  • 实现了迭代器的常用方法,负责逐个访问集合的元素。

模板方法模式的优点和缺点

优点
  1. 封装集合的访问逻辑:使用迭代器访问集合元素,而无需了解集合的内部结构。
  2. 统一接口:不同类型的集合可以通过相同的迭代器接口进行遍历。
  3. 灵活性:可以扩展支持更多类型的集合或迭代方式。
缺点
  1. 类的数量增加:每种集合都需要一个具体的迭代器类。
  2. 性能开销:迭代器的实现可能会引入额外的性能开销。

总结

迭代器模式是一个非常实用的设计模式,特别适合需要顺序访问集合元素的场景。在本案例中,我们通过迭代器模式实现了图书馆书籍集合的遍历,展示了如何解耦集合的访问逻辑和实现细节。

适用场景
  1. 遍历复杂数据结构:如链表、树、图等。
  2. 提供统一的遍历接口:使得不同集合的遍历方式一致。

迭代器模式的核心思想是分离集合的存储和访问逻辑,在实际开发中非常常见,例如C++标准库中的std::vectorstd::list的迭代器实现!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

极客晨风

感谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值