如何重构这个6行方法以使其更具可读性?

时间:2009-11-23 01:18:44

标签: ruby oop readability refactoring code-readability

我正试图在这里清理这个非常丑陋的方法,这是为了重构而哭泣,但我不确定哪种结构会做到最好(即一个案例陈述,或者只是一个精心格式化的{{1语句)

乍一看,它似乎是一个案例陈述的理想位置,有一些位置很好的if then,但我的理解是case语句只能用于单个变量,不是两个,并且使用哈希或数组来尝试这些语句的各种小提琴也没有在这里发挥很大的作用。

你会怎么做?在检查这样的多个布尔值时,Ruby中是否有任何常见的技巧来避免这样的代码?

when

4 个答案:

答案 0 :(得分:13)

伙计们 - 这里的多态性似乎需要通过在一种方法中摆弄流量控制来解决。

这是我从扩展版本开始的尝试:

def has_just_one_kind_of_thing?(item, controller)
  (controller == 'foos' && item.widgets.blank?)    || 
  (controller == 'foos' && item.doohickeys.blank?) || 
  (controller == 'bars' && item.widgets.blank?)    || 
  (controller == 'bars' && item.doohickeys.blank?) || 
  (controller == 'bazes' && item.widgets.blank?)   || 
  (controller == 'bazes' && item.contraptions.blank?)
end

所以有三种不同的行为 - 每个控制器一个 ....如果每个控制器足够聪明以包含特定于控制器的决策,并且您传入实际控制器而不仅仅是一个名称控制器,你将方法减少到这个:

def has_just_one_kind_of_thing?(item, controller)
  controller.has_just_one_kind_of_thing?(item)
end

这要求每个控制器对其所属的控制器进行相关的项目处理。因此,让我们在每个foos,bar和bazes上定义一个方法,称为has_just_one_kind_of_thing?

foos的例子:

def has_just_one_kind_of_thing?(item)
   item.widgets.blank? || item.doohickeys.blank?
end

bazes的例子:

def has_just_one_kind_of_thing?(item)
   item.widgets.blank? || item.contraptions.blank?
end

在您要返回false的每个控制器上,只需应用“常量方法”模式:

def has_just_one_kind_of_thing?(item)
  false
end

这段代码甚至运行得更快,因为现在,我们不必像控制器类型那样进行多次检查 - 我们只对控制器执行一次方法调度。

所以它在解释的ruby中更快 - 并且甚至可能在jruby 或其他可以大大优化方法调度的其他红宝石中快得多...... / p>

我们可能会让它变得更聪明,但我需要知道这种方法所处的类别,以及关于item的其他一些事情。

替代重构应该是item聪明,并且对每种类型的item使用不同的方法。同样,我们需要了解更多有关对象模型的信息,以确定最佳...

仍然是第一次削减。

答案 1 :(得分:10)

这样的东西,也许?

def has_just_one_kind_of_thing?(item, controller)
    return case controller
      when 'foos', 'bars'
        item.widgets.blank? || item.doohickeys.blank?
      when 'bazes'
        item.widgets.blank? || item.contraptions.blank?
      else 
        false
    end
  end

外部回报可能没有必要(不完全确定Ruby需要什么,我自己还是相当新的),但我更喜欢把它放进去,所以意图很明显。

答案 2 :(得分:4)

首先,Ruby总是默认返回最后一个语句的值,所以我们可以去掉if / else:

def has_just_one_kind_of_thing?(item, controller)
    (controller == 'foos' && item.widgets.blank?) || (controller == 'foos' && item.doohickeys.blank?) || (controller == 'bars' && item.widgets.blank?) || (controller == 'bars' && item.doohickeys.blank?) || (controller == 'bazes' && item.widgets.blank?) || (controller == 'bazes' && item.contraptions.blank?)
end

现在让我们重新格式化以便于阅读。

def has_just_one_kind_of_thing?(item, controller)
  (controller == 'foos' && item.widgets.blank?)    || 
  (controller == 'foos' && item.doohickeys.blank?) || 
  (controller == 'bars' && item.widgets.blank?)    || 
  (controller == 'bars' && item.doohickeys.blank?) || 
  (controller == 'bazes' && item.widgets.blank?)   || 
  (controller == 'bazes' && item.contraptions.blank?)
end

现在,在算法中看到模式要容易得多。看起来这里有两个问题:控制器是[foos | bars | bazes]中的一个,是小部件还是doohickeys空白。让我们分解第一个问题:

def has_just_one_kind_of_thing?(item, controller)
  %w[foos bars bazes].include?(controller)  &&
    (item.widgets.blank? || item.doohickeys.blank?)
end

这会将方法降低到可管理的大小。但我从方法名称推断出你正在寻找小部件或doohickeys有项目但不是两者而​​不是两者都没有的情况。如果是这样,则XOR可能更合适:

def has_just_one_kind_of_thing?(item, controller)
  %w[foos bars bazes].include?(controller)  &&
    (item.widgets.blank? ^ item.doohickeys.blank?)
end

答案 3 :(得分:3)

de Morgan的布尔逻辑定理有两个陈述。

1。 (A和B)等同于(notA或notB)

not(A和B)等同于(notA或notB)

2。 (A或B)等同于(notA和notB)

not(A或B)等同于(notA和notB)

...

  1. 买三明治(少于2美元,是鲑鱼) =如果是(不低于2美元或不是鲑鱼),不要买三明治。

  2. 观看电视,如果(V开启或阿凡达打开) =如果(V关闭且阿凡达关闭),请不要看电视。

  3. 进一步的布尔代数,等等,

    1. (A和B)或(A和C) = A和(B或C)

    2. (A或B)或C. = A或B或C


    3. 原始逻辑:

        (controller == 'foos' && item.widgets.blank?)    || 
        (controller == 'foos' && item.doohickeys.blank?) || 
      
        (controller == 'bars' && item.widgets.blank?)    || 
        (controller == 'bars' && item.doohickeys.blank?) || 
      
        (controller == 'bazes' && item.widgets.blank?)   || 
        (controller == 'bazes' && item.contraptions.blank?)
      


      减少
      (foos和widgets)或(foos and hickeys)= foos和(小部件或hickeys):

        (
          (controller == 'foos' &&
            (item.widgets.blank? || item.doohickeys.blank?)
          ) || 
      
          (controller == 'bars' &&
            (item.widgets.blank? || item.doohickeys.blank?)
          ) || 
      
          (controller == 'bazes' &&
            (item.widgets.blank? || item.contraptions.blank?)
          )
        )
      


      减少
      (foos和items)或(酒吧和物品)=(foos或bars)和物品:

        (
          (controller == 'foos' || controller == 'bars') &&
          (item.widgets.blank? || item.doohickeys.blank?)
        ) ||
      
        (controller == 'bazes' &&
          (item.widgets.blank? || item.contraptions.blank?)
        )
      


      逻辑减少从原来的6行减少到3.5行。 虽然这个练习并不涉及de Morgan但是纯粹的布尔代数操作,de Morgan's常常适用于其他情况。

      你可能会说,每当我们写一堆逻辑语句时,为什么我必须去做这样的麻烦?简化的逻辑与原始逻辑没有任何相似之处,也不是很好的自我记录代码。

      完全!减少的逻辑让你用简单的术语来看待它,而原始的东西与你本来应该拥有的简单逻辑没有任何相似之处。