Ruby / Rails中的类方法与常量

时间:2013-04-09 13:53:30

标签: ruby-on-rails ruby

我正在实现一个包含一个硬编码下拉列表的表单,我想知道什么是最好的解决方案,我知道两种方式都暴露在工作之下,我仍然如下:

class Example

  # Options for Example.
  self.options
    [ 'Yes', 'No', 'Not sure' ]
  end
end

Example.options调用,但我知道也可以这样做:

class Example

  # Options for Example.
  OPTIONS = [ 'Yes', 'No', 'Not sure' ]
end

将使用Example::OPTIONS调用。

问题是,这些中的任何一种都是好方法,还是根本不重要?

4 个答案:

答案 0 :(得分:35)

后者更好。如果它是一个方法,每次调用时都会创建一个新数组和新字符串,这会浪费资源。

答案 1 :(得分:31)

TL; DR:这取决于。这些值是否意味着在课外使用?他们会变得充满活力吗?他们可以改变子类吗?

正如@sawa所写,该方法的缺点(以这种方式编写)是每次都创建一个新的数组和字符串。

更好的写作方式是:

class Example
  def self.options
    @options ||= ['Yes', 'No', 'Not sure']
  end
end

数组存储在实例变量@options中,以避免每次都创建新数组。

以这种方式编写,该方法与常量非常相似。

一个关键区别是如果Example是子类,则优化options方法比使用常量OPTIONS更自然:

class Parent < Example
  def self.options
    @options ||= [*super, 'Extra']
  end
end

要做与常数类似的事情很难。想象一下,您的选项列表在类方法中使用,如下所示:

class Example
  OPTIONS = ['Yes', 'No', 'Not sure']

  def self.foo(arg)
     puts "Available options:",
          self::OPTIONS  # The self:: is needed here
     # ...
  end
end

class Parent < Example
  OPTIONS = [*superclass::OPTIONS, 'Extra']
end

关于常量的棘手问题是self::OPTIONSOPTIONS并不总是相同,而self.optionsoptions是相同的。通常使用常量而不指定范围(例如OPTIONS而不是self::OPTIONS),并且继承在这种情况下根本不起作用。

请注意,该方法使您有机会在不更改API的情况下使结果动态化(即根据其他情况返回不同的结果)。

最后说明:我建议您在阵列上调用freeze,以避免任何人修改它。

答案 2 :(得分:7)

我通常做的是混合使用上述技术:

class Player
  JURISDICTIONS = %i(de uk ru)

  def self.jurisdictions
    JURISDICTIONS
  end
end

它没什么优势:

  • 它提供了一个干净的界面,封装了一个常量(您调用Player.jurisdictions而不是Player::JURISDICTIONS)。
  • 只需改变方法即可添加其他逻辑。
  • 该方法可以在测试中存根。
恕我直言,这里的表现并不重要。

<强>更新: 可以使用private_constant方法(http://ruby-doc.org/core-2.3.0/Module.html#method-i-private_constant

隐藏常量

答案 3 :(得分:1)

为了进一步细化Artur的建议,我会使用类变量来隐藏常量的可见性。

class Player
  @@jurisdictions = %i(de uk ru)

  def self.jurisdictions
    @@jurisdictions
  end
end