编写多行懒惰计算方法的红宝石方法是什么?

时间:2012-06-27 20:11:18

标签: ruby

我认为我可能不会以最红宝石的方式编写懒惰的实例化方法/属性。以此方法为例:

def tax
  @tax ||= Proc.new do
    if flat_tax > commission_plan.tax_max
      return commission_plan.tax_max
    end if commission_plan.tax_max
    if flat_tax < commission_plan.tax_min
      return commission_plan.tax_min
    end if commission_plan.tax_min
    flat_tax
  end.call
end

有没有更像红宝石的方法来重构这个方法?

4 个答案:

答案 0 :(得分:6)

def tax
  @tax ||= calc_tax
end

private

def calc_tax
  min, max = commission_plan.tax_min, commission_plan.tax_max
  if (min..max).include? flat_tax
    flat_tax
  else
    flat_tax > max ? max : min
  end
end

答案 1 :(得分:2)

你在问什么叫做Memoization。正如Yuri建议的那样,你为此使用Proc是很尴尬的。

这是我的快速重构。我可能仍然会进一步重构......但这是一个简单的重构,它更像Ruby-ish。

def tax
  @tax ||= calculate_tax
end

def calculate_tax
  if commission_plan.tax_max && flat_tax > commission_plan.tax_max
    commission_plan.tax_max
  elsif commission_plan.tax_min && flat_tax < commission_plan.tax_min
    commission_plan.tax_min
  else 
    flat_tax
  end
end

此外,如果您不介意包含一些外部依赖项,请查看ActiveSupport::Memoizable。这篇文章讨论memoization

答案 2 :(得分:2)

如果您不想向外部库添加依赖项,则可以轻松添加自己的“memoize”帮助程序。有点像:

class Class
  def memoize(method)
    original_method = instance_method(method)
    instance_var = "@__#{method}__".to_sym
    define_method(method) do |*a,&b|
      cached = instance_variable_get(instance_var)
      unless cached
        cached = old_method.bind(self).call(*a,&b)
        instance_variable_set(instance_var, cached)
      end
      cached
    end
  end
end

然后使用就像:

def tax
  # expensive calculation here
end
memoize :tax

如果您不喜欢这个memoize界面,可以将其更改为您喜欢的任何内容。这是Ruby,宝贝!你可以像泡泡糖一样扭曲,弯曲和伸展的语言。也许像这样的界面会很好:

def_memoized :tax do
  # expensive calculation here
end

我喜欢将我的每个项目扩展项放在名为lib/core_extensions.rb的文件中的核心Ruby中。这就是那种情况。

答案 3 :(得分:1)

我不明白你为什么要创建这个匿名函数。这是......多余的。这是一个更好,更清洁的代码:

def tax
    return commission_plan.tax_max if commission_plan.tax_max &&
        flat_tax > commission_plan.tax_max
    return commission_plan.tax_min if commission_plan.tax_min &&
        flat_tax > commission_plan.tax_min
    return flat_tax
end

还有其他方法可以实现它,但与你的相比,这是一个很大的进步。