基于odoo17的設計模式詳解---構建模式

大家好,我是你的Odoo技術伙伴。在Odoo開發中,創建一個簡單的記錄可能只需要一行 self.env['res.partner'].create({'name': 'New Partner'})。但如果我們要創建一個復雜的對象,比如一個包含了特定上下文、具有多個可選配置、并且需要執行一系列關聯操作的銷售訂單,傳統的create()方法可能會變得非常臃腫和難以閱讀。

為了解決這個問題,軟件設計領域提出了構建者模式(Builder Pattern)。今天,我們將深入探討這一模式,并揭示Odoo是如何通過其獨特的API設計,特別是鏈式調用(Method Chaining),將構建者模式的思想融入日常開發,幫助我們以一種更清晰、更靈活的方式來構造和配置對象。

一、什么是構建者模式?

讓我們先從一個現實世界的例子開始:定制一臺電腦

當你去電腦品牌的官網定制一臺電腦時,你不會看到一個包含所有可能配置(CPU、內存、硬盤、顯卡…)的、擁有幾十個參數的巨大表單。相反,你會經歷一個分步的過程:

  1. 選擇基礎型號(產品)。
  2. 第一步:選擇CPU。
  3. 第二步:選擇內存大小。
  4. 第三步:選擇硬盤類型和容量。
  5. 最后一步:確認配置并下單(生成最終產品)。

這個過程就是構建者模式的體現:

  • 產品(Product): 最終配置好的那臺電腦。
  • 構建者(Builder): 官網的配置頁面。它提供了一系列分步設置的方法(selectCPU(), selectRAM()),并內部維護著正在構建的電腦配置。
  • 指揮者(Director) (可選): 可能是一個“推薦配置”按鈕,它會按照預設的順序調用構建者的各個方法,來快速生成一個“游戲玩家”或“辦公文員”套餐。

構建者模式的核心思想是:將一個復雜對象的構建過程與其表示相分離,使得同樣的構建過程可以創建不同的表示。它特別適用于當一個對象的創建需要多個步驟,或者其構造函數參數過多時。

二、Odoo中的構建者思想:鏈式調用與上下文

在Odoo中,你很少會需要自己去創建一個ComputerBuilder這樣的類。Odoo的ORM和API設計,尤其是**記錄集(Recordset)**的鏈式調用能力,天然地扮演了構建者的角色。

在Odoo中,記錄集自身就是構建者,而其上的方法就是構建者的步驟。

經典案例:搜索查詢的構建

Odoo的search()方法是構建者模式最直觀的應用之一。雖然它看起來只是一行調用,但其返回的記錄集可以被看作是一個“查詢構建者”的結果,這個構建者可以被進一步配置。

傳統的search()調用

partners = self.env['res.partner'].search([('is_company', '=', True), ('country_id', '=', 'US')],order='name asc',limit=10,offset=5
)

這里,search()方法的多個參數扮演了配置步驟的角色。但更強大的構建者思想體現在鏈式調用上。

讓我們想象一個更“構建者風格”的查詢API(這并非Odoo原生API,僅為說明思想):

# 這是一個假設的、更純粹的Builder風格API
query_builder = self.env['res.partner'].builder() # 1. 獲取構建者partners = query_builder.where([('is_company', '=', True)]) \.where([('country_id', '=', 'US')]) \.order_by('name asc') \.limit(10) \.offset(5) \.execute() # 2. 執行構建,返回產品

雖然Odoo沒有提供這樣的builder()方法,但它的ORM通過返回self(即記錄集本身) 的方法,實現了類似的效果。

記錄集操作的鏈式調用

Odoo的記錄集方法,如filtered(), sorted(), with_context(), with_company()等,都返回一個新的、被修改過的記錄集實例。這使得我們可以將它們鏈接起來,一步步地“構建”出我們最終想要操作的目標數據集。

場景:獲取美國的所有公司客戶,按名稱排序,并以管理員權限(忽略記錄規則)讀取他們的郵箱。

# 1. 初始產品:所有伙伴的記錄集
all_partners = self.env['res.partner'].search([])# 2. 開始分步構建
final_partners_to_process = all_partners \.filtered(lambda p: p.is_company and p.country_id.code == 'US') \.sorted(key=lambda p: p.name) \.sudo() # 以超級用戶權限構建下一步的操作環境# 3. 獲取最終結果(表示)
emails = final_partners_to_process.mapped('email')

代碼解讀:

  • all_partners: 我們的基礎“原材料”。
  • .filtered(...): 第一步,過濾出公司和國家。返回一個新的、過濾后的記錄集。
  • .sorted(...): 第二步,對上一步的結果進行排序。返回一個新的、排好序的記錄集。
  • .sudo(): 第三步,為下一步操作切換用戶上下文。返回一個新的、具有sudo權限的記錄集。
  • final_partners_to_process: 這 Risk Management,這就是我們通過構建者模式,一步步構造出來的“待處理對象”。
  • .mapped('email'): 最后,我們從這個構造好的對象中提取出我們想要的數據(表示)。

每一個鏈式調用,都像是在定制電腦的流程中完成了一個配置步驟。這種方式比將所有邏輯都塞進一個復雜的search()或一個巨大的循環中,要清晰得多。

with_context(): 構建者的“環境配置”

with_context()方法是Odoo中構建者模式思想的又一絕佳體現。它允許你為一個即將進行的操作,臨時構建一個特定的上下文環境,而不影響全局狀態。

場景:以英文環境創建一張發票,無論當前用戶的語言是什么。

# 1. 獲取一個基礎的“發票創建者”(即模型代理)
InvoiceBuilder = self.env['account.move']# 2. 使用 with_context() 來配置構建環境
InvoiceBuilderWithLang = InvoiceBuilder.with_context(lang='en_US')# 3. 在配置好的環境中,執行創建操作
new_invoice = InvoiceBuilderWithLang.create({'partner_id': some_partner.id,'move_type': 'out_invoice',
})
# 這張發票中的默認描述、稅名等都會是英文的。

在這里,with_context()方法并沒有改變InvoiceBuilder本身,而是返回了一個新的、攜帶了特定上下文的代理對象(構建者)。這使得構建過程更加靈活和安全。with_company()with_user()也是同理。

四、優勢與適用場景

優勢

  • 代碼可讀性強: 分步的、鏈式的調用讓復雜的構建邏輯一目了然。
  • 靈活性高: 客戶端可以根據需要,自由組合構建步驟,或者只執行, 其中幾步。
  • 封裝性好: 將復雜的構建邏輯封裝在構建步驟(方法)中,使得客戶端代碼更加簡潔。
  • 支持不可變性: 像with_context這樣的方法返回的是新對象,保證了原始構建者(模型代理)的不可變性,更加安全。

何時應用構建者思想?

在你的自定義模塊中,當你需要設計一個方法來執行一個多步驟、多配置的復雜操作時,就可以借鑒構建者模式:

  • 設計返回self的方法: 如果你的方法主要是為了配置或修改一個對象的狀態,并希望支持鏈式調用,那么讓它返回self(或一個新的記錄集實例)。
  • 提供配置方法: 與其設計一個有十幾個參數的“上帝方法”,不如將其拆分為多個配置方法和一個最終的執行方法。

示例:一個自定義的報告生成器

class MyReportGenerator(models.AbstractModel):_name = 'my.report.generator'def new(self, records):self.records = recordsself.config = {}return self # 返回自身,支持鏈式調用def with_header(self, header_text):self.config['header'] = header_textreturn selfdef include_details(self, detailed=True):self.config['detailed'] = detailedreturn selfdef generate(self):# ... 根據 self.records 和 self.config 生成報告 ...return report_data# 使用
report_data = self.env['my.report.generator'] \.new(some_records) \.with_header("My Custom Report") \.include_details(True) \.generate()

結論

構建者模式在Odoo中并非一個顯式的、需要你去繼承的Builder類,而是一種內化于ORM和API設計中的強大思想。它通過鏈式調用和上下文切換方法(with_context等),將復雜對象的構造過程分解為一系列清晰、可讀、可組合的步驟。

理解并運用這一模式,將幫助你:

  • 更好地利用Odoo ORM的強大功能,寫出更優雅、更高效的數據處理代碼。
  • 在設計自己的模塊API時,創建出更加靈活和易于使用的接口。

下次當你面對一個復雜的對象創建或配置任務時,不妨停下來想一想“定制電腦”的例子,嘗試用構建者模式的思路,將它分解為一步步清晰的鏈式調用吧。

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

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

相關文章

暑假算法日記第四天

目標?:刷完靈神專題訓練算法題單 階段目標📌:【算法題單】滑動窗口與雙指針 LeetCode題目:2953. 統計完全子字符串1016. 子串能表示從 1 到 N 數字的二進制串其他: 今日總結 往期打卡 2953. 統計完全子字符串 跳轉: 2953. 統計完全子字符串…

Linux 常用命令大全(2025簡明版)

🧭 一、文件和目錄操作命令說明ls列出目錄內容ls -l以列表形式顯示(含權限)cd /path切換目錄pwd顯示當前路徑mkdir dir創建目錄mkdir -p dir/subdir遞歸創建目錄rm file刪除文件rm -r dir刪除目錄(遞歸)rm -rf dir強制…

React Ref 指南:原理、實現與實踐

前言 React Ref(引用)是React中一個強大而重要的概念,它為我們提供了直接訪問DOM元素或組件實例的能力。雖然React推崇聲明式編程和數據驅動的理念,但在某些場景下,我們仍需要直接操作DOM或訪問組件實例。本文將深入探…

4.權重衰減(weight decay)

4.1 手動實現權重衰減 import torch from torch import nn from torch.utils.data import TensorDataset,DataLoader import matplotlib.pyplot as plt def synthetic_data(w,b,num_inputs):Xtorch.normal(0,1,size(num_inputs,w.shape[0]))yXwbytorch.normal(0,0.1,sizey.shap…

OpenCV開發-初始概念

第一章 OpenCV核心架構解析1.1 計算機視覺的基石OpenCV(Open Source Computer Vision Library)作為跨平臺計算機視覺庫,自1999年由Intel發起,已成為圖像處理領域的標準工具。其核心價值體現在:跨平臺性:支持…

LeetCode 930.和相同的二元子數組

給你一個二元數組 nums ,和一個整數 goal ,請你統計并返回有多少個和為 goal 的 非空 子數組。 子數組 是數組的一段連續部分。 示例 1: 輸入:nums [1,0,1,0,1], goal 2 輸出:4 解釋: 有 4 個滿足題目要求…

【論文解讀】Referring Camouflaged Object Detection

論文信息 論文題目:Referring Camouflaged Object Detection 論文鏈接:https://arxiv.org/pdf/2306.07532 代碼鏈接:https://github.com/zhangxuying1004/RefCOD 錄用期刊:TPAMI 2025 論文單位:南開大學 ps&#xff1a…

Spring中過濾器和攔截器的區別及具體實現

在 Spring 框架中,過濾器(Filter) 和 攔截器(Interceptor) 都是用于處理 HTTP 請求的中間件,但它們在作用范圍、實現方式和生命周期上有顯著區別。以下是詳細對比和實現方式:核心區別特性過濾器…

CANFD 數據記錄儀在新能源汽車售后維修中的應用

一、前言隨著新能源汽車市場如火如荼和新能源汽車電子系統的日益復雜,傳統維修手段在面對復雜和偶發故障時往往捉襟見肘,CANFD 數據記錄儀則憑借其獨特優勢,為售后維修帶來新的解決方案。二、 詳細介紹在新能源汽車領域,CANFD 數據…

某當CRM XlsFileUpload存在任意文件上傳(CNVD-2025-10982)

免責聲明 本文檔所述漏洞詳情及復現方法僅限用于合法授權的安全研究和學術教育用途。任何個人或組織不得利用本文內容從事未經許可的滲透測試、網絡攻擊或其他違法行為。使用者應確保其行為符合相關法律法規,并取得目標系統的明確授權。 前言: 我們建立了一個更多,更全的…

自然語言處理與實踐

文章目錄Lesson1:Introduction to NLP、NLP 基礎與文本預處理1.教材2.自然語言處理概述(1)NLP 的定義、發展歷程與應用場景(2)NLP 的主要任務:分詞、詞性標注、命名實體識別、句法分析等2.文本預處理3.文本表示方法:詞向量表示/詞表征Lesson2…

CSS揭秘:9.自適應的橢圓

前置知識:border-radius 用法前言 本篇目標是實現一個橢圓,半橢圓,四分之一橢圓。 一、圓形和橢圓 當我們想實現一個圓形時,通常只要指定 border-radius 為 width/height 的一半就可以了。 當我們指定的border-radius的值超過了 w…

善用關系網絡:開源AI大模型、AI智能名片與S2B2C商城小程序賦能下的成功新路徑

摘要:本文聚焦于關系在個人成功中的關鍵作用,指出關系即財富,善用關系、拓展人脈是成功的重要途徑。在此基礎上,引入開源AI大模型、AI智能名片以及S2B2C商城小程序等新興技術工具,探討它們如何助力個體在復雜的關系網絡…

2025年滲透測試面試題總結-2025年HW(護網面試) 34(題目+回答)

安全領域各種資源,學習文檔,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各種好玩的項目及好用的工具,歡迎關注。 目錄 2025年HW(護網面試) 34 一、網站信息收集 核心步驟與工具 二、CDN繞過與真實IP獲取 6大實戰方法 三、常…

螢石全新上線企業AI對話智能體,開啟IoT人機交互新體驗

一、什么是螢石AI對話智能體?如何讓設備聽得到、聽得懂?這次螢石發布的AI對話Agent,讓設備能進行自然、流暢、真人感的AI對話智能體,幫助開發者打造符合業務場景的AI對話智能體能力,實現全雙工、實時打斷、可擴展、對話…

智紳科技:以科技為翼,構建養老安全守護網

隨著我國老齡化進程加速,2025年60歲以上人口突破3.2億,養老安全問題成為社會關注的焦點。智紳科技作為智慧養老領域的領軍企業,以“科技賦能健康,智慧守護晚年”為核心理念,通過人工智能、物聯網、大數據等技術融合&am…

矩陣系統源碼部署實操指南:搭建全解析,支持OEM

矩陣系統源碼部署指南矩陣系統是一種高效的數據處理框架,適用于大規模分布式計算。以下為詳細部署步驟,包含OEM支持方案。環境準備確保服務器滿足以下要求:操作系統:Linux(推薦Ubuntu 18.04/CentOS 7)硬件配…

基于python的個人財務記賬系統

博主介紹:java高級開發,從事互聯網行業多年,熟悉各種主流語言,精通java、python、php、爬蟲、web開發,已經做了多年的畢業設計程序開發,開發過上千套畢業設計程序,沒有什么華麗的語言&#xff0…

從 CODING 停服到極狐 GitLab “接棒”,軟件研發工具市場風云再起

CODING DevOps 產品即將停服的消息,如同一顆重磅炸彈,在軟件研發工具市場炸開了鍋。從今年 9 月開始,CODING 將陸續下線其 DevOps 產品,直至 2028 年 9 月 30 日完全停服。這一變動讓眾多依賴 CODING 平臺的企業和個人開發者陷入了…

#滲透測試#批量漏洞挖掘#HSC Mailinspector 任意文件讀取漏洞(CVE-2024-34470)

免責聲明 本教程僅為合法的教學目的而準備,嚴禁用于任何形式的違法犯罪活動及其他商業行為,在使用本教程前,您應確保該行為符合當地的法律法規,繼續閱讀即表示您需自行承擔所有操作的后果,如有異議,請立即停…