設計模式Python版 訪問者模式

文章目錄

  • 前言
  • 一、訪問者模式
  • 二、訪問者模式示例


前言

GOF設計模式分三大類:

  • 創建型模式:關注對象的創建過程,包括單例模式、簡單工廠模式、工廠方法模式、抽象工廠模式、原型模式和建造者模式。
  • 結構型模式:關注類和對象之間的組合,包括適配器模式、橋接模式、組合模式、裝飾模式、外觀模式、享元模式和代理模式。
  • 行為型模式:關注對象之間的交互,包括職責鏈模式、命令模式、解釋器模式、迭代器模式、中介者模式、備忘錄模式、觀察者模式、狀態模式、策略模式、模板方法模式和訪問者模式。

一、訪問者模式

訪問者模式(Visitor Pattern)

  • 定義:提供一個作用于某對象結構中的各元素的操作表示,它使得可以在不改變各元素的類的前提下定義作用于這些元素的新操作。

  • 解決問題:如何操作一個包含多種類型對象的復雜結構?

  • 使用場景:

    • 當系統中存在一個較為復雜的對象結構,且不同訪問者對其所采取的操作也不相同時,可以考慮使用訪問者模式進行設計。
    • 一個對象結構包含多種類型的對象,希望對這些對象實施一些依賴其具體類型的操作。在訪問者中針對每一種具體的類型都提供了一個訪問操作,不同類型的對象可以有不同的訪問操作。
  • 組成:

    • Visitor(抽象訪問者):抽象訪問者為對象結構中每個具體元素類ConcreteElement聲明一個訪問操作,從這個操作的名稱或參數類型可以清楚知道需要訪問的具體元素的類型。
    • ConcreteVisitor(具體訪問者):具體訪問者實現了每個由抽象訪問者聲明的操作,每個操作用于訪問對象結構中一種類型的元素。
    • Element(抽象元素):定義一個accept()方法,該方法通常以一個抽象訪問者作為參數。
    • ConcreteElement(具體元素):具體元素實現了accept()方法,在accept()方法中調用訪問者的訪問方法以便完成對一個元素的操作。
    • ObjectStructure(對象結構):對象結構是一個元素的集合,它用于存放元素對象,并且提供了遍歷其內部元素的方法。
  • 補充說明:

    • 訪問者模式,包含訪問者和被訪問元素兩個主要組成部分。
    • 這些被訪問的元素通常具有不同的類型,且不同的訪問者可以對它們進行不同的訪問操作。
    • 被訪問的元素通常存儲在一個集合中,這個集合稱為“對象結構”。訪問者通過遍歷對象結構實現對其中存儲的元素的逐個操作。
    • 訪問者模式包括兩個層次結構:一個是訪問者層次結構,提供了抽象訪問者和具體訪問者;另一個是元素層次結構,提供了抽象元素和具體元素。
  • 優點:

    • 增加新的訪問操作很方便。
    • 將有關元素對象的訪問行為集中到一個訪問者對象中,而不是分散在一個個的元素類中。類的職責更加清晰。
  • 缺點:

    • 增加新的元素類很困難。
    • 破壞封裝。

在這里插入圖片描述

二、訪問者模式示例

使用訪問者模式,設計系統中員工數據匯總模塊

  • 員工包括正式員工和臨時工,每周人力資源部和財務部等部門需要對員工數據進行匯總。人力資源部負責匯總每周員工工作時間,而財務部負責計算每周員工工資。
    • 正式員工每周工作時間為40小時。不同級別、不同部門的員工每周基本工資不同。如果超過40小時,超出部分按照100元/小時作為加班費;如果少于40小時,所缺時間按照請假處理,請假所扣工資以80元/小時計算,直到基本工資扣除到零為止。
    • 臨時工每周工作時間不固定。基本工資按小時計算,不同崗位的臨時工小時工資不同。
  • FADepartment表示財務部,HRDepartment表示人力資源部,它們充當具體訪問者角色,其抽象父類Department充當抽象訪問者角色;
  • EmployeeList充當對象結構,用于存儲員工列表;
  • FulltimeEmployee表示正式員工,ParttimeEmployee表示臨時工,它們充當具體元素角色,其父接口Employee充當抽象元素角色。
"""訪問者模式"""### 抽象訪問者class Departement:"""部門"""def visit_fulltime_employee(self, employee: "FulltimeEmployee"):raise NotImplementedErrordef visit_parttime_employee(self, employee: "ParttimeEmployee"):raise NotImplementedError### 具體訪問者class Finance(Departement):"""財務部"""def visit_fulltime_employee(self, employee):"""實現財務部對全職員工的訪問"""if employee.work_time > 40:employee.weekly_wage = (employee.weekly_wage + (employee.work_time - 40) * 100)else:employee.weekly_wage = (employee.weekly_wage - (40 - employee.work_time) * 100)if employee.weekly_wage < 0:employee.weekly_wage = 0print(f"正式員工:{employee.name},實際工資為:{employee.weekly_wage}")def visit_parttime_employee(self, employee):"""實現人事部對兼職員工的訪問"""print(f"兼職員工:{employee.name},實際工資為:{employee.work_time*employee.hourly_wage}")class HR(Departement):"""人事部"""def visit_fulltime_employee(self, employee):"""實現人事部對全職員工的訪問"""print(f"正式員工:{employee.name},實際工作時間:{employee.work_time}")if employee.work_time > 40:print(f"正式員工:{employee.name},加班時間為:{employee.work_time - 40}")else:print(f"正式員工:{employee.name},請假時間為:{40-employee.work_time}")def visit_parttime_employee(self, employee):"""實現人事部對兼職員工的訪問"""print(f"兼職員工:{employee.name},實際工作時間:{employee.work_time}")### 抽象元素class Employee:"""員工"""def accept(self, handler: Departement):"""接受一個抽象訪問者訪問"""raise NotImplementedError### 具體元素class FulltimeEmployee(Employee):"""全職員工"""def __init__(self, name: str, weekly_wage: float, work_time: int):self.name = name  # 員工姓名self.weekly_wage = weekly_wage  # 員工周薪self.work_time = work_time  # 工作時間def accept(self, handler):handler.visit_fulltime_employee(self)  # 調用訪問者的訪問方法class ParttimeEmployee(Employee):"""兼職員工"""def __init__(self, name: str, hourly_wage: float, work_time: int):self.name = name  # 員工姓名self.hourly_wage = hourly_wage  # 員工時薪self.work_time = work_time  # 工作時間def accept(self, handler):handler.visit_parttime_employee(self)  # 調用訪問者的訪問方法### 對象結構class EmployeeList:"""員工列表"""def __init__(self):self.employees = []def add_employee(self, employee):self.employees.append(employee)def accept(self, departement):for employee in self.employees:employee.accept(departement)def __str__(self):return "\n".join([str(employee) for employee in self.employees])
  • 客戶端代碼
### 客戶端代碼
if __name__ == "__main__":employee_list = EmployeeList()employee_list.add_employee(FulltimeEmployee("張三", 5000, 45))employee_list.add_employee(FulltimeEmployee("李四", 6000, 40))employee_list.add_employee(FulltimeEmployee("王五", 7000, 38))employee_list.add_employee(ParttimeEmployee("趙六", 80, 20))employee_list.add_employee(ParttimeEmployee("孫七", 60, 18))dep: Departement = Finance()# 如果需要更換具體訪問者類,無須修改源代碼,只需修改配置文件。# dep: Departement = HR()employee_list.accept(dep)
  • 輸出結果
正式員工:張三,實際工資為:5500
正式員工:李四,實際工資為:6000
正式員工:王五,實際工資為:6800
兼職員工:趙六,實際工資為:1600
兼職員工:孫七,實際工資為:1080
  • 當訪問者更換為HR時,輸出結果
正式員工:張三,實際工作時間:45
正式員工:張三,加班時間為:5
正式員工:李四,實際工作時間:40
正式員工:李四,請假時間為:0
正式員工:王五,實際工作時間:38
正式員工:王五,請假時間為:2
兼職員工:趙六,實際工作時間:20
兼職員工:孫七,實際工作時間:18

您正在閱讀的是《設計模式Python版》專欄!關注不迷路~

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

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

相關文章

安全無事故連續天數計算,python 時間工具的高效利用

安全天數計算&#xff0c;數據系統時間直取&#xff0c;安全標準高效便捷好用。 筆記模板由python腳本于2025-03-17 23:50:52創建&#xff0c;本篇筆記適合對python時間工具有研究欲的coder翻閱。 【學習的細節是歡悅的歷程】 博客的核心價值&#xff1a;在于輸出思考與經驗&am…

大型語言模型(LLM)部署中的內存消耗計算

在部署大型語言模型&#xff08;LLM&#xff09;時&#xff0c;顯存&#xff08;VRAM&#xff09;的合理規劃是決定模型能否高效運行的核心問題。本文將通過詳細的公式推導和示例計算&#xff0c;系統解析模型權重、鍵值緩存&#xff08;KV Cache&#xff09;、激活內存及額外開…

Mysql表的查詢

一&#xff1a;創建一個新的數據庫&#xff08;companydb),并查看數據庫。 二&#xff1a;使用該數據庫&#xff0c;并創建表worker。 mysql> use companydb;mysql> CREATE TABLE worker(-> 部門號 INT(11) NOT NULL,-> 職工號 INT(11) NOT NULL,-> 工作時間 D…

ASP.NET Webform和ASP.NET MVC 后臺開發 大概80%常用技術

本文涉及ASP.NET Webform和ASP.NET MVC 后臺開發大概80%技術 2019年以前對標 深圳22K左右 廣州18K左右 武漢16K左右 那么有人問了2019年以后的呢&#xff1f; 答&#xff1a;吉祥三寶。。。 So 想繼續看下文的 得有自己的獨立判斷能力。 C#.NET高級筆試題 架構 優化 性能提…

首頁性能優化

首頁性能提升是前端優化中的核心任務之一&#xff0c;因為首頁是用戶訪問的第一入口&#xff0c;其加載速度和交互體驗直接影響用戶的留存率和轉化率。 1. 性能瓶頸分析 在優化之前&#xff0c;首先需要通過工具分析首頁的性能瓶頸。常用的工具包括&#xff1a; Chrome DevTo…

一周學會Flask3 Python Web開發-SQLAlchemy刪除數據操作-班級模塊

鋒哥原創的Flask3 Python Web開發 Flask3視頻教程&#xff1a; 2025版 Flask3 Python web開發 視頻教程(無廢話版) 玩命更新中~_嗶哩嗶哩_bilibili 首頁list.html里加上刪除鏈接&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta c…

改變一生的思維模型【12】笛卡爾思維模型

目錄 基本結構 警惕認知暗礁 案例分析應用 一、懷疑階段:破除慣性認知 二、解析階段:拆解問題為最小單元 三、整合階段:重構邏輯鏈條 四、檢驗階段:多維驗證解決方案 總結與啟示 笛卡爾說,唯獨自己的思考是可以相信的。 世界上所有的事情,都是值得被懷疑的,但是…

需求文檔(PRD,Product Requirement Document)的基本要求和案例參考:功能清單、流程圖、原型圖、邏輯能力和表達能力

文章目錄 引言I 需求文檔的基本要求結構清晰內容完整語言準確圖文結合版本管理II 需求文檔案例參考案例1:電商平臺“商品中心”功能需求(簡化版)案例2:教育類APP“記憶寶盒”非功能需求**案例3:軟件項目的功能需求模板3.1 功能需求III 需求文檔撰寫技巧1. **從核心邏輯出發…

五大方向全面對比 IoTDB 與 OpenTSDB

對比系列第三彈&#xff0c;詳解 IoTDB VS OpenTSDB&#xff01; 之前&#xff0c;我們已經深入探討了時序數據庫 Apache IoTDB 與 InfluxDB、Apache HBase 在架構設計、性能和功能方面等多個維度的區別。還沒看過的小伙伴可以點擊閱讀&#xff1a; Apache IoTDB vs InfluxDB 開…

Electron使用WebAssembly實現CRC-16 MAXIM校驗

Electron使用WebAssembly實現CRC-16 MAXIM校驗 將C/C語言代碼&#xff0c;經由WebAssembly編譯為庫函數&#xff0c;可以在JS語言環境進行調用。這里介紹在Electron工具環境使用WebAssembly調用CRC-16 MAXIM格式校驗的方式。 CRC-16 MAXIM校驗函數WebAssembly源文件 C語言實…

vue3vue-elementPlus-admin框架中form組件的upload寫法

dialog中write組件代碼 let ImageList reactive<UploadFile[]>([])const formSchema reactive<FormSchema[]>([{field: ImageFiles,label: 現場圖片,component: Upload,colProps: { span: 24 },componentProps: {limit: 5,action: PATH_URL /upload,headers: {…

Linux mount和SSD分區

為什么要用 mount&#xff1f; Linux 的文件系統結構是單一的樹狀層次 所有文件、目錄和設備都從根目錄 / 開始延伸。 外部的存儲設備&#xff08;如硬盤、U盤、網絡存儲&#xff09;或虛擬文件系統&#xff08;如 /proc、/sys&#xff09;必須通過掛載點“嫁接”到這棵樹上&a…

【Function】Azure Function通過托管身份或訪問令牌連接Azure SQL數據庫

【Function】Azure Function通過托管身份或訪問令牌連接Azure SQL數據庫 推薦超級課程: 本地離線DeepSeek AI方案部署實戰教程【完全版】Docker快速入門到精通Kubernetes入門到大師通關課AWS云服務快速入門實戰目錄 【Function】Azure Function通過托管身份或訪問令牌連接Azu…

舉例說明 牛頓法 Hessian 矩陣

矩陣求逆的方法及示例 目錄 矩陣求逆的方法及示例1. 伴隨矩陣法2. 初等行變換法矩陣逆的實際意義1. 求解線性方程組2. 線性變換的逆操作3. 數據分析和機器學習4. 優化問題牛頓法原理解釋舉例說明 牛頓法 Hessian 矩陣1. 伴隨矩陣法 原理:對于一個 n n n 階方陣 A A

安科瑞分布式光伏監測系統:推動綠色能源高效發展

安科瑞顧強 為應對傳統能源污染與資源短缺&#xff0c;分布式光伏發電成為關鍵解決方案。安科瑞Acrel-1000DP分布式光伏監控系統結合光功率預測技術&#xff0c;有效提升發電穩定性&#xff0c;助力上海汽車變速器有限公司8.3MW屋頂光伏項目實現清潔能源高效利用。 項目亮點 …

從零開始使用 **Taki + Node.js** 實現動態網頁轉靜態網站的完整代碼方案

以下是從零開始使用 Taki Node.js 實現動態網頁轉靜態網站的完整代碼方案&#xff0c;包含預渲染、自動化構建、靜態托管及優化功能&#xff1a; 一、環境準備 1. 初始化項目 mkdir static-site && cd static-site npm init -y2. 安裝依賴 npm install taki expre…

商業智能BI分析中,汽車4S銷售行業的返廠頻次有什么分析價值?

買過車的朋友會發現&#xff0c;同一款車不管在哪個4S店去買&#xff0c;基本上價格都相差不大。即使有些差別&#xff0c;也是帶著附加條件的&#xff0c;比如要做些加裝需要額外再付一下費用。為什么汽車4S銷售行業需要商業智能BI&#xff1f;就是因為在汽車4S銷售行業&#…

靜態鏈接過程發生了什么?

在靜態鏈接過程中主要發生了兩件事。一是空間與地址分配&#xff0c;鏈接器掃描所有輸入文件的段&#xff0c;合并相似段并且重新計算段長度和在虛擬內存中的映射關系&#xff0c;收集所有的符號放到全局符號表中。二是符號解析與重定位&#xff0c;鏈接器收集所有的段信息和重…

? 一次有趣的經歷

&#x1f4c6;2025年3月17日 | 周一 | ??晴 &#x1f4cd;今天路過學院樓7&#xff0c;見到了滿園盛開的花&#x1f33a;&#xff0c;心情瞬間明朗&#xff01; &#x1f4cc;希望接下來的日子也能像這些花一樣&#xff0c;充滿活力&#x1f525;&#xff01; &#x1…

docker安裝redis

第一步&#xff1a;docker拉取redis鏡像 這種命令如果沒有指定版本則是最新版本&#xff1a;docker pull redis 成功了 docker images 查詢已經拉取成功鏡像 然后因為在容器內部我們修改redis的配置不好修改&#xff0c;所以我們可以進行掛載配置文件 這個配置文件可以方便…