You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用服务对象模式应用迪米特法则?附代码合规性验证问询

关于迪米特法则与服务对象模式的疑问解答

好问题!咱们一步步来拆解你的疑问:

一、existent_order方法是否违反迪米特法则?

答案是确实有违反的嫌疑。

先回忆下迪米特法则的核心:一个对象应该只和自己的「直接朋友」打交道,不要随意操作朋友的内部细节(也就是朋友的朋友)。

看你代码里的这段链式调用:

organization.orders.with_external_id(external_id).first

这里organization是服务对象的直接朋友(初始化时传入的依赖),但orders是organization的内部集合属性,with_external_id又是这个集合的方法——相当于你直接伸手去操作朋友的私人物品,还调用了私人物品的专属方法,这就越界了。服务对象根本不需要知道organization内部有orders这个集合,也不需要知道集合有with_external_id这个查询方法,它只需要知道「能不能从这个组织里找到对应外部ID的订单」就够了。

二、如何用服务对象模式应用迪米特法则?

服务对象的核心是封装单一业务逻辑,同时要尽量减少对象间的耦合。针对你的场景,我们可以通过以下方式重构:

1. 把内部查询逻辑封装到依赖对象中

让Organization类自己负责「根据外部ID找订单」的逻辑,而不是让服务对象深入到它的内部结构。给Organization新增一个方法:

class Organization
  # ... 其他原有代码
  def find_order_by_external_id(external_id)
    orders.with_external_id(external_id).first
  end
end

2. 重构服务对象的代码

修改CreateOrderService里的existent_order方法,只和直接朋友organization做单一交互:

class CreateOrderService
  def initialize(organization, order_params)
    @organization = organization
    @order_params = order_params
  end

  private
  def not_exists?
    existent_order.blank?
  end

  def existent_order
    @existent_order ||= organization.find_order_by_external_id(external_id)
  end

  def create
    # some code to create an order...
  end

  attr_reader :organization, :order_params

  # 补充获取external_id的逻辑(假设从order_params中提取)
  def external_id
    order_params[:external_id]
  end
end

3. 额外的设计小技巧

  • 服务对象只做「流程控制」:专注于创建订单的业务流程,不要承担查询其他对象内部数据的职责
  • 隐藏内部实现细节:每个对象只暴露必要的接口,比如Organization只暴露find_order_by_external_id,而不是直接把orders集合对外抛出
  • 警惕链式调用:以后再看到a.b.c.d这种多层调用,先停下来想想是不是违反了迪米特法则,尽量拆成单一的方法调用

这样重构后,服务对象和Organization的耦合度大幅降低——哪怕以后Organization内部存储订单的方式变了(比如换集合类型、改查询逻辑),服务对象完全不需要修改,只要Organization维护好find_order_by_external_id这个接口就行。

内容的提问来源于stack exchange,提问作者Bruno Fernandes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:05:53