基于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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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)

免责声明 本教程仅为合法的教学目的而准备,严禁用于任何形式的违法犯罪活动及其他商业行为,在使用本教程前,您应确保该行为符合当地的法律法规,继续阅读即表示您需自行承担所有操作的后果,如有异议,请立即停…