設計模式:迭代器模式(Iterator Pattern)

文章目錄

    • 一、概念
    • 二、實例分析
    • 三、示例代碼

一、概念

??迭代器模式 是一種 行為型設計模式,用于在不暴露集合對象內部結構的前提下,順序訪問集合中的元素。

換句話說:

  • 集合類只負責數據存儲;
  • 迭代器類負責遍歷集合;
  • 使用者不需要關心集合內部是數組、鏈表還是樹。

在這里插入圖片描述

迭代器模式一般包含以下角色:

  1. Iterator(抽象迭代器):定義訪問元素的接口,比如 first()、next()、hasNext()、currentItem()。
  2. ConcreteIterator(具體迭代器):實現 Iterator 接口,負責跟蹤遍歷位置。
  3. Aggregate(抽象聚合類):定義創建迭代器的接口。
  4. 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");
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/921232.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/921232.shtml
英文地址,請注明出處:http://en.pswp.cn/news/921232.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Vue 3 學習路線指南

階段一:基礎入門 (1-2周) 1.1 環境準備 # 安裝 Node.js (推薦 18+ 版本) # 安裝 Vue CLI 或使用 Vite npm create vue@latest my-vue-app cd my-vue-app npm install npm run dev1.2 Vue 3 核心概念 響應式系統:ref(), reactive(), computed() 組合式 API:setup() 函數 模…

使用 `hover:not-[:has(:hover)]` 避免「父元素和子元素同時 hover」時的樣式沖突

:hover:not-(:has(:hover)) has() CSS 4 引入的“父選擇器”&#xff0c;意思是&#xff1a;匹配那些里面包含某個子元素/狀態的元素。 例如&#xff1a;:has(:hover) 表示「自身包含正在被 hover 的子元素」。 :not() 取反偽類&#xff0c;表示不匹配里面的條件。 比如我…

第三十天-DMA串口實驗

一、DMA概述二、DMA通道注意&#xff0c;想要往串口中寫數據&#xff0c;外部請求信號應該是USARTx_TX&#xff0c;當DR寄存器為空時&#xff0c;產生TX信號&#xff0c;請求DMA。反之&#xff0c;從串口中讀數據&#xff0c;外部請求信號應該是USARTx_RX&#xff0c;當DR寄存器…

C/C++ 中的inline(內聯函數關鍵字)詳解

在 C/C 編程中&#xff0c;函數調用雖然帶來了代碼復用和可讀性提升&#xff0c;但頻繁調用小型函數可能會產生額外的調用開銷&#xff08;call overhead&#xff09;&#xff0c;比如棧幀的建立與銷毀、參數傳遞等。 為了減少這種開銷&#xff0c;C 引入了 inline&#xff08;…

2025 年高教社杯全國大學生數學建模競賽A 題 煙幕干擾彈的投放策略完整成品 思路 模型 代碼 結果 全網首發高質量!!!

煙幕干擾彈主要通過化學燃燒或爆炸分散形成煙幕或氣溶膠云團,在目標前方特定空域形成遮蔽&#xff0c;干擾敵方導彈&#xff0c;具有成本低、效費比高等優點。隨著煙幕干擾技術的不斷發展&#xff0c;現已有多種投放方式完成煙幕干擾彈的定點精確拋撒,即在拋撒前能精確控制煙幕…

嵌入式第四十五天(51單片機相關)

一.1.CPU、MPU、MCU、GPU&#xff1a; CPU&#xff08;中央處理器&#xff09;&#xff1a;計算機的核心部件&#xff0c;負責執行指令和處理數據。 MPU&#xff08;微處理器&#xff09;&#xff1a;通常指更通用的處理器&#xff0c;強調計算能力。 MCU&#xff08;微控制器&…

今天面了一個Java后端工程師,真的讓我猛抬頭

今天面了一個Java后端工程師,真的讓我猛抬頭啊. 現在面試不像傳統的八股文面試,我更多問的都是項目場景相關的問題,但是都能回答的不錯.這一點我還是很驚訝的。 不僅如此,她的技術也很扎實,對Java核心機制&#xff08;JVM、并發、集合等&#xff09;理解深入&#xff0c;回答…

攔截器和過濾器(理論+實操)

攔截器和過濾器 本文旨在夯實基礎以及實戰加深理解,目的是更深的理解以便掌握,希望能跟著動手敲一遍,絕對受益匪淺 在本文,我會先給出兩者的區別(理論知識),隨后是兩者各自的實操實現 文章目錄攔截器和過濾器什么是過濾器和攔截器?1.過濾器2.攔截器執行整體流程攔截器和過濾器…

HTB 賽季8靶場 - Guardian

各位好&#xff0c;最近我的kali崩掉了&#xff0c;崩掉了&#xff0c;建議大家避K 番茄C盤瘦身&#xff0c;這家伙修改了我的avrt.dll文件&#xff0c;導致virtualbox不接受我的avrt.dll文件的簽名了&#xff0c;從而導致virtualbox的虛擬機環境全崩無法開機。弄了幾天&#x…

Rust+slint實現一個登錄demo

系列文章目錄 文章目錄系列文章目錄前言一、為什么前端選擇slint而不是Tauri或者其他GUI框架二、開發工具三、代碼編寫項目結構前端代碼編寫后端開發編寫運行效果總結前言 本文章就是一個簡單rust全棧編程的一個小小的示例供rust新手閱讀學習。 一、為什么前端選擇slint而不是…

2025前端面試題及答案(詳細)

HTML5 的新特性有哪些&#xff1f;簡約版本&#xff1a;“HTML5 新特性主要體現在六個方面&#xff1a; 第一&#xff0c;語義化標簽&#xff0c;比如 header、footer、nav 等&#xff0c;讓頁面結構更清晰&#xff1b; 第二&#xff0c;表單增強&#xff0c;新增了 date、emai…

分詞器詳解(二)

&#x1f50d; 第2層&#xff1a;中等深度&#xff08;15分鐘理解&#xff09; 1. 理論基礎 1.1 BPE的數學原理 核心思想&#xff1a;通過迭代合并高頻字符對構建詞匯表 算法形式化&#xff1a; 初始化詞匯表 V0{c1,c2,...,cn}V_0 \{c_1, c_2, ..., c_n\}V0?{c1?,c2?,...,c…

嵌入式學習 51單片機(3)

UART 概述通用異步收發器&#xff08;UART&#xff09;是一種全雙工、串行、異步通信協議&#xff0c;常用于設備間數據傳輸。包含兩根信號線&#xff1a;RXD&#xff08;接收信號線&#xff09;TXD&#xff08;發送信號線&#xff09;通信方式單工通信方向固定&#xff0c;僅支…

Redis AOF 持久化:銀行的 “交易流水單” 管理邏輯

目錄 一、AOF 的核心邏輯&#xff1a;“每筆交易都記流水” 二、AOF 的三個步驟&#xff1a;從 “臨時記錄” 到 “正式歸檔” 1. 命令追加&#xff1a;記到 “臨時小本本” 2. 寫入與同步&#xff1a;抄到 “正式流水冊” 3. AOF 還原&#xff1a;拿 “流水冊” 重放交易…

代碼隨想錄訓練營第三十天|LeetCode452.用最少數量的箭引爆氣球、LeetCode435.無重疊空間、LeetCode763.劃分字母空間

452.用最少數量的箭引爆氣球 貪心算法 重合最多的氣球射一箭&#xff0c;就是局部用箭數量最少的&#xff0c;全局的用箭數量就是最少的。 首先對二維數組進行排序&#xff0c;這樣就可以讓氣球更加緊湊。 思路&#xff1a;當前氣球是否和上一個氣球區間重合&#xff0c;如…

數據庫事務隔離級別與 MVCC 機制詳解

最近在準備面試&#xff0c;正把平時積累的筆記、項目中遇到的問題與解決方案、對核心原理的理解&#xff0c;以及高頻業務場景的應對策略系統梳理一遍&#xff0c;既能加深記憶&#xff0c;也能讓知識體系更扎實&#xff0c;供大家參考&#xff0c;歡迎討論。在數據庫并發操作…

【Cursor-Gpt-5-high】StackCube-v1 任務訓練結果不穩定性的分析

1. Prompt 我是機器人RL方向的博士生正在學習ManiSkill&#xff0c;在學習時我嘗試使用相同命令訓練同一個任務&#xff0c;但是我發現最終的 success_once 指標并不是相同的&#xff0c;我感到十分焦慮&#xff0c; 我使用的命令如下&#xff1a; python sac.py --env_id"…

文檔權限設置不合理會帶來哪些問題

文檔權限設置不合理會導致信息泄露、合規風險、協作效率下降、責任難以追溯、知識資產流失、員工信任受損、管理成本增加、企業戰略受阻。這些問題不僅影響日常運營&#xff0c;更會對企業的長遠發展構成威脅。根據IBM《2024數據泄露成本報告》&#xff0c;全球企業因數據泄露的…

Linux網絡服務——基礎設置

網絡服務命令1.ping命令作用&#xff1a;測試網絡連通性&#xff08;使用icmp協議&#xff09;常見選項&#xff1a;-c&#xff1a;指定ping的次數&#xff0c;默認無限次-I&#xff1a;指定發送請求的網卡[rootlocalhost ~]# ping 192.168.77.78 -c 4 -I ens160 PING 192.168.…

【multisim汽車尾燈設計】2022-12-1

緣由multisim汽車尾燈設計-學習和成長-CSDN問答 為什么模仿別人做的運行沒啥效果&#xff0c;啥也看不明白&#xff0c;數字電子技術要做的任務。