大家好,我是你的Odoo技术伙伴。在Odoo这个高度模块化的平台上,一个核心的业务流程,比如“从销售订单创建发票”,往往需要多个模块的协作。sale
模块负责创建基础发票,sale_stock
模块关联库存信息,自定义的sale_loyalty
模块可能计算并添加忠诚度折扣。这些模块如何协作,既完成各自任务,又互不干扰、无需知晓彼此的存在?答案就是职责链模式(Chain of Responsibility Pattern)。
一、什么是职责链模式?
通过一个现实世界的审批流程来理解:
假设公司有一笔费用报销申请:
- 申请单提交给直接经理(Handler 1)。若金额在其权限内,他批准,流程结束。
- 若金额超限,他不拒绝,而是将申请单传递给部门总监(Handler 2)。
- 总监审核,若金额在其权限内,他批准;否则,继续传递给财务副总裁(Handler 3),依此类推。
职责链模式的核心思想:避免请求的发送者和接收者耦合,让多个对象都有机会处理请求。将这些对象连成一条链,请求沿链传递,直到被处理。
- 请求(Request):费用报销申请。
- 处理者(Handler):经理、总监、副总裁。
- 链(Chain):经理 -> 总监 -> 副总裁。
发送者(员工)只需将请求“扔”到链的开端,无需知道谁最终处理。
二、Odoo的精髓:super()
就是那条链
在Odoo中,职责链模式通过ORM的继承机制实现,super()
函数是连接这条链的关键。
- 请求:方法调用,如
sale_order._create_invoices()
。 - 处理者:继承并重写该方法的每个模块中的类。
- 链:由Odoo的方法解析顺序(MRO)决定的
super()
调用序列。
当多个模块继承同一模型并重写同一方法时,它们自动形成职责链。
场景剖析:多模块协作创建发票
目标:扩展“从销售订单创建发票”的流程。
- 基础处理者:
sale
模块,_create_invoices()
创建基本发票。 - 处理者A:
sale_project
模块,为发票关联项目信息。 - 处理者B:
sale_loyalty
模块,添加忠诚度折扣。
1. 基础处理者 (sale
模块)
# addons/sale/models/sale_order.py
class SaleOrder(models.Model):
_name = 'sale.order'
def _create_invoices(self, grouped=False, final=False, date=None):
# 核心逻辑:创建 account.move 并返回
invoices = self.env['account.move'].create(invoice_vals_list)
print("Handler: sale (Base) - Basic invoice created.")
return invoices
2. 处理者A (sale_loyalty
模块)
# addons/my_sale_loyalty/models/sale_order.py
class SaleOrderLoyalty(models.Model):
_inherit = 'sale.order'
def _create_invoices(self, grouped=False, final=False, date=None):
# 先传递请求给链上的下一个处理者
invoices = super(SaleOrderLoyalty, self)._create_invoices(grouped, final, date)
# 执行自己的逻辑
print("Handler: sale_loyalty - Checking for loyalty discounts...")
for invoice in invoices:
if invoice.partner_id.is_loyal:
# 添加折扣行逻辑
print(f" -> Added loyalty discount to invoice {invoice.name}")
return invoices
3. 处理者B (sale_project
模块)
假设sale_project
依赖sale_loyalty
。
# addons/my_sale_project/models/sale_order.py
class SaleOrderProject(models.Model):
_inherit = 'sale.order'
def _create_invoices(self, grouped=False, final=False, date=None):
# 先传递请求
invoices = super(SaleOrderProject, self)._create_invoices(grouped, final, date)
# 执行自己的逻辑
print("Handler: sale_project - Linking project to invoice...")
for invoice in invoices.filtered(lambda inv: inv.order_id.project_id):
invoice.project_id = inv.order_id.project_id
print(f" -> Linked project to invoice {invoice.name}")
return invoices
链的执行顺序
当用户点击“创建发票”:
- 由于
sale_project
依赖sale_loyalty
,MRO为[SaleOrderProject, SaleOrderLoyalty, SaleOrder, ...]
。 super()
调用链:SaleOrderProject._create_invoices()
调用super()
。- 请求传递至
SaleOrderLoyalty._create_invoices()
,它调用super()
。 - 请求传递至
SaleOrder._create_invoices()
,创建基础发票,返回invoices
。 SaleOrderLoyalty
接收invoices
,添加折扣,返回修改后的invoices
。SaleOrderProject
接收invoices
,关联项目信息,返回最终结果。
输出日志:
Handler: sale_project - Linking project to invoice...
Handler: sale_loyalty - Checking for loyalty discounts...
Handler: sale (Base) - Basic invoice created.
-> Added loyalty discount to invoice INV/2023/0001
-> Linked project to invoice INV/2023/0001
(注:打印顺序与执行顺序相反,因print
在super()
之后)
三、职责链模式的优势与注意事项
优势
- 终极解耦:模块间完全解耦,可随时安装/卸载模块,系统仍正常运行。
- 高度可扩展:新增处理者(如
sale_commission
模块)只需继承模型、重写方法、调用super()
。 - 单一职责:每个模块的逻辑封装在自己的方法中,职责清晰,易维护。
注意事项
super()
是生命线:若忘记调用super()
,链中断,上游逻辑被跳过,可能导致严重bug。- 顺序可能重要:模块依赖关系决定MRO,需仔细设计(如先计算总额再折扣)。
- 请求不一定被处理:Odoo中基础方法通常确保核心处理,职责链更注重“增强”。
结论
职责链模式是Odoo模块化架构的基石,通过_inherit
和super()
融入日常开发。运用此模式,扩展核心功能时:
- 继承相关模型。
- 重写目标方法。
- 方法首行调用
super()
。 - 对
super()
返回结果进行增强。
掌握职责链模式,你将构建松耦合、高内聚、易维护的Odoo应用,领会其设计精髓。