【问题标题】:Object Oriented way to deal with complicated method面向对象的方式处理复杂的方法
【发布时间】:2012-05-23 15:10:46
【问题描述】:

我有一个正在使用 ruby​​ 进行的项目,它需要一些工人的大量工作。大多数业务逻辑都包含在这些工作人员中,它们变得相当复杂。我设计的技术模拟了 compose 方法模式,但它严重依赖实例变量来保持状态。我设置它的方式似乎合乎逻辑,但我想从社区获得一些反馈,看看这是否有误,或者不是我可以设置的最干净的方式。

我基本上是在使用 worker perform (Sidekiq) 方法作为一种开关

def perform(transaction_id, data, account_id)
  @transaction_id = transaction_id
  @data           = data
  @account        = Account.new(account_id)

  @campaign_tag   = nil
  @match_str      = nil
  @options        = nil

  has_starter_tag     || return
  find_campaign       || return
  determine_options   || return
  find_active_option  || return
  reservation_over    || return
  already_filled      || return

  send_to_inventory
end

每种方法都遵循相同的逻辑。检查规则,如果不满意,执行操作(发送电子邮件等)并返回 false,从而停止执行。如果满意,则存储一些完成事务所需的 ivar 数据并返回 true,从而进入下一步。

def has_starter_tag
  result = true

  @campaign_tag = find_starter_tag(@account, @data[:variable])
  if !@campaign_tag
    result = false
    send_email_about_badness
    log_some_stuff
  end

  result
end

为了测试这段代码,我对每个方法所依赖的实例变量进行了存根。我知道这是一种代码味道,因为我的测试知道实现而不是接口。也就是说,我喜欢这些方法的干净界面,我觉得我可以扫描源代码并确切地知道发生了什么。

如果我做错了,有人可以花点时间解释一下正确的方法(或至少另一种方法)吗?我一直无法弄清楚如何处理那些必须执行许多似乎相互依赖的小步骤的对象。

【问题讨论】:

  • 如何使用在工作线程中设置的前三个实例变量? @campaignmatch_stroptions 是用来做什么的?首先,我会让has_starter_tag 和其他方法接受它们每个人都需要的参数。这将让您测试分离,而不是依赖于实例变量。
  • 我更新了示例方法,以便更好地说明如何使用它。前 3 个变量本质上是大多数方法用于数据的常量。我可能应该指定这一点,但我在从has_starter_tag 外部方法中调用的方法中完成大部分工作。这些不访问实例变量,并且是单独进行单元测试的。

标签: ruby oop


【解决方案1】:

我的直觉是你试图在某种程度上过度设计它。

您所描述的内容不算作一种设计模式——它只是将所需的功能分成许多单独的方法。问题是这些方法彼此紧密耦合,以至于将它们分开除了“分组”功能之外没有多大用途。这些功能似乎唯一的共同点是它们检查某些内容并取消检查失败的工作。除了重复的功能,你可以通过将所有代码放在一个函数中并用空行分隔各个部分来实现大致相同的效果。

有时在代码中找到一些 OOP 解决方案或设计模式可能会适得其反。归根结底,真正重要的是,它是否提供了优势?它会保存代码吗?它是否使代码易于维护和扩展? (代码需要易于扩展吗?)不要为了OOP而尝试使用OOP。

【讨论】:

    猜你喜欢
    • 2019-09-06
    • 2019-04-25
    • 2011-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-24
    • 1970-01-01
    相关资源
    最近更新 更多