文章目錄
- 一、概念
- 二、實例分析
- 三、示例代碼
一、概念
??迭代器模式 是一種 行為型設計模式,用于在不暴露集合對象內部結構的前提下,順序訪問集合中的元素。
換句話說:
- 集合類只負責數據存儲;
- 迭代器類負責遍歷集合;
- 使用者不需要關心集合內部是數組、鏈表還是樹。
迭代器模式一般包含以下角色:
- Iterator(抽象迭代器):定義訪問元素的接口,比如 first()、next()、hasNext()、currentItem()。
- ConcreteIterator(具體迭代器):實現 Iterator 接口,負責跟蹤遍歷位置。
- Aggregate(抽象聚合類):定義創建迭代器的接口。
- ConcreteAggregate(具體聚合類):實現 Aggregate,返回一個具體迭代器對象。
迭代器模式結構:
二、實例分析
問題:
集合是編程中最常使用的數據類型之一。 盡管如此, 集合只是一組對象的容器而已。
大部分集合使用簡單列表存儲元素。 但有些集合還會使用棧、 樹、 圖和其他復雜的數據結構。
無論集合的構成方式如何, 它都必須提供某種訪問元素的方式, 便于其他代碼使用其中的元素。 集合應提供一種能夠遍歷元素的方式, 且保證它不會周而復始地訪問同一個元素。
如果你的集合基于列表, 那么這項工作聽上去仿佛很簡單。 但如何遍歷復雜數據結構 (例如樹) 中的元素呢? 例如, 今天你需要使用深度優先算法來遍歷樹結構, 明天可能會需要廣度優先算法; 下周則可能會需要其他方式 (比如隨機存取樹中的元素)。
不斷向集合中添加遍歷算法會模糊其 “高效存儲數據” 的主要職責。 此外, 有些算法可能是根據特定應用訂制的, 將其加入泛型集合類中會顯得非常奇怪。
另一方面, 使用多種集合的客戶端代碼可能并不關心存儲數據的方式。 不過由于集合提供不同的元素訪問方式, 你的代碼將不得不與特定集合類進行耦合。
解決方案:
迭代器模式的主要思想是將集合的遍歷行為抽取為單獨的迭代器對象。
除實現自身算法外, 迭代器還封裝了遍歷操作的所有細節, 例如當前位置和末尾剩余元素的數量。 因此, 多個迭代器可以在相互獨立的情況下同時訪問集合。
迭代器通常會提供一個獲取集合元素的基本方法。 客戶端可不斷調用該方法直至它不返回任何內容, 這意味著迭代器已經遍歷了所有元素。
所有迭代器必須實現相同的接口。 這樣一來, 只要有合適的迭代器, 客戶端代碼就能兼容任何類型的集合或遍歷算法。 如果你需要采用特殊方式來遍歷集合, 只需創建一個新的迭代器類即可, 無需對集合或客戶端進行修改。
三、示例代碼
示例一:
#include <iostream>
#include <vector>
#include <memory>
using namespace std;// 抽象迭代器
class Iterator {
public:virtual bool hasNext() = 0;virtual int next() = 0;virtual ~Iterator() = default;
};// 抽象聚合類
class Aggregate {
public:virtual unique_ptr<Iterator> createIterator() = 0;virtual ~Aggregate() = default;
};// 具體聚合類
class ConcreteAggregate : public Aggregate {
private:vector<int> items;
public:void add(int item) { items.push_back(item); }vector<int>& getItems() { return items; }unique_ptr<Iterator> createIterator() override;
};// 具體迭代器
class ConcreteIterator : public Iterator {
private:ConcreteAggregate& aggregate;size_t index = 0;
public:ConcreteIterator(ConcreteAggregate& agg) : aggregate(agg) {}bool hasNext() override {return index < aggregate.getItems().size();}int next() override {return aggregate.getItems()[index++];}
};// 工廠方法實現
unique_ptr<Iterator> ConcreteAggregate::createIterator() {return make_unique<ConcreteIterator>(*this);
}// 測試
int main() {ConcreteAggregate agg;agg.add(10);agg.add(20);agg.add(30);auto it = agg.createIterator();while (it->hasNext()) {cout << it->next() << " ";}return 0;
}
示例二:
上圖展示的是一個社交網絡遍歷的迭代器模式實現,核心思想是:
- SocialNetwork 定義了創建迭代器的接口(好友迭代器、同事迭代器)。
- WeChat 是具體的社交網絡實現,能返回具體迭代器。
- ProfileIterator 是迭代器接口,統一規定 getNext() / hasMore()。
- WeChatIterator 是具體的迭代器實現,負責按不同方式遍歷好友或同事。
- Application 只依賴 SocialNetwork 和 ProfileIterator 接口,不依賴具體實現。
#include <iostream>
#include <string>
#include <vector>
#include <memory>
using namespace std;// ==================== Profile ====================
class Profile {string id;string email;
public:Profile(string i, string e) : id(move(i)), email(move(e)) {}string getId() const { return id; }string getEmail() const { return email; }
};// ==================== 迭代器接口 ====================
class ProfileIterator {
public:virtual bool hasMore() = 0;virtual shared_ptr<Profile> getNext() = 0;virtual ~ProfileIterator() = default;
};// ==================== 社交網絡接口 ====================
class SocialNetwork {
public:virtual unique_ptr<ProfileIterator> createFriendsIterator(const string& profileId) = 0;virtual unique_ptr<ProfileIterator> createCoworkersIterator(const string& profileId) = 0;virtual ~SocialNetwork() = default;
};// ==================== WeChat 迭代器 ====================
class WeChat; // 前向聲明class WeChatIterator : public ProfileIterator {WeChat* weChat;string profileId;string type; // friends / coworkerssize_t currentPosition = 0;vector<shared_ptr<Profile>> cache;public:WeChatIterator(WeChat* wc, string id, string t): weChat(wc), profileId(move(id)), type(move(t)) {lazyInit();}void lazyInit();bool hasMore() override {return currentPosition < cache.size();}shared_ptr<Profile> getNext() override {if (!hasMore()) return nullptr;return cache[currentPosition++];}
};// ==================== WeChat 網絡實現 ====================
class WeChat : public SocialNetwork {vector<shared_ptr<Profile>> profiles;
public:void addProfile(shared_ptr<Profile> p) { profiles.push_back(p); }// 簡單模擬:好友=所有偶數下標,同事=所有奇數下標vector<shared_ptr<Profile>> requestProfiles(const string& id, const string& type) {vector<shared_ptr<Profile>> result;for (size_t i = 0; i < profiles.size(); i++) {if ((type == "friends" && i % 2 == 0) ||(type == "coworkers" && i % 2 == 1)) {result.push_back(profiles[i]);}}return result;}unique_ptr<ProfileIterator> createFriendsIterator(const string& profileId) override {return make_unique<WeChatIterator>(this, profileId, "friends");}unique_ptr<ProfileIterator> createCoworkersIterator(const string& profileId) override {return make_unique<WeChatIterator>(this, profileId, "coworkers");}
};// WeChatIterator 延遲加載實現
void WeChatIterator::lazyInit() {if (cache.empty()) {cache = weChat->requestProfiles(profileId, type);}
}// ==================== 應用層(發垃圾消息) ====================
class SocialSpammer {
public:void send(ProfileIterator& it, const string& message) {while (it.hasMore()) {auto profile = it.getNext();cout << "Send '" << message << "' to " << profile->getEmail() << endl;}}
};class Application {SocialSpammer spammer;shared_ptr<SocialNetwork> network;
public:Application(shared_ptr<SocialNetwork> net) : network(move(net)) {}void sendSpamToFriends(const string& profileId) {auto it = network->createFriendsIterator(profileId);spammer.send(*it, "Hello Friend!");}void sendSpamToCoworkers(const string& profileId) {auto it = network->createCoworkersIterator(profileId);spammer.send(*it, "Hello Coworker!");}
};// ==================== 測試 ====================
int main() {auto wechat = make_shared<WeChat>();wechat->addProfile(make_shared<Profile>("001", "a@example.com"));wechat->addProfile(make_shared<Profile>("002", "b@example.com"));wechat->addProfile(make_shared<Profile>("003", "c@example.com"));wechat->addProfile(make_shared<Profile>("004", "d@example.com"));Application app(wechat);cout << "=== 發送給好友 ===" << endl;app.sendSpamToFriends("001");cout << "=== 發送給同事 ===" << endl;app.sendSpamToCoworkers("001");
}