重构圈复杂性

时间:2017-07-24 21:15:54

标签: ruby refactoring

我的这段代码具有很高的圈复杂度:

def status_icon_name
  return 'icons/new.png' if mailgun_id.blank?
  return 'icons/hourglass.png' if mailgun_id.present? && log.blank?

  return 'icons/accept.png' if log['event'] == 'delivered'
  return 'icons/exclamation.png' if log['severity'].present? && log['severity'] == 'permanent'
  return 'icons/time.png' if log['event'] == 'accepted'
  return 'icons/error.png' if log['severity'] == 'temporary' 
  return 'icons/question.gif'
end

如何重构它以消除圈复杂度?

我已经阅读了这篇博文Cyclomatic complexity refactoring tips for javascript developers并提出了类似的内容,但对我来说感觉不对:

def status_icon_name
  lookup = [
    {
      condition: mailgun_id.blank?,
      icon_name: 'icons/new.png'
    },
    {
      condition: mailgun_id.present? && log.blank?,
      icon_name: 'icons/hourglass.png'
    },
    {
      condition: log.present? && log['event'] == 'delivered',
      icon_name: 'icons/accept.png'
    },
    {
      condition: log.present? && log['severity'].present? && log['severity'] == 'permanent',
      icon_name: 'icons/exclamation.png'
    },
    {
      condition: log.present? && log['event'] == 'accepted',
      icon_name: 'icons/time.png'
    },
    {
      condition: log.present? && log['severity'] == 'temporary',
      icon_name: 'icons/error.png'
    },
    {
      condition: true,
      icon_name: 'icons/question.gif'
    }
  ]

  lookup.find { |x| x[:condition] }[:icon_name]
end

1 个答案:

答案 0 :(得分:5)

在运行时构建这样的查找表会产生反作用,您将生成这个庞大的结构并评估所有这些条件,无论其有效性如何。

也就是说,当你写:

lookup = [
  {
    condition: mailgun_id.blank?,
    icon_name: 'icons/new.png'
  }
]

立即评估并简化为:

lookup = [
  {
    condition: true,
    icon_name: 'icons/new.png'
  }
]

如果您想延期执行,则需要使用Proc

LOOKUP = [
  {
    condition: Proc.new { mailgun_id.blank? },
    icon_name: 'icons/new.png'
  }
]

然后你执行如下:

LOOKUP.find { |x| instance_eval(&x[:condition]) }[:icon_name]

通过这种方式,您可以将查找表存储为类顶部的常量,只需要定义一次,而不是每次方法调用一次。