Ruby/Rails中的类方法与常量

9fkzdhlc  于 2023-03-22  发布在  Ruby
关注(0)|答案(4)|浏览(114)

我正在实现一个表单,其中包括一个集合的硬编码下拉列表,我想知道什么是最好的解决方案,我知道下面暴露的两种方式都可以工作,但我还是按照以下方式做了:

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
问题是,这些是好方法还是根本不重要?

k2arahey

k2arahey1#

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

rks48beu

rks48beu2#

视情况而定。这些值是要在类之外使用的吗?它们会变成动态的吗?它们会为子类而改变吗?
正如@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,以避免任何人修改它。

ffx8fchx

ffx8fchx3#

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

class Player
  JURISDICTIONS = %i(de uk ru)

  def self.jurisdictions
    JURISDICTIONS
  end
end

它有几个优点:

  • 它提供了一个干净的接口,封装了一个常量(调用Player.jurisdictions而不是Player::JURISDICTIONS)。
  • 以后可以通过改变方法来添加其他逻辑。
  • 方法可以在测试中存根化。

IMHO,性能在这里并不重要。

更新:可以使用private_constant方法隐藏常量(http://ruby-doc.org/core-2.3.0/Module.html#method-i-private_constant)

oewdyzsn

oewdyzsn4#

为了进一步完善Artur的建议,我将使用一个类变量来隐藏常量的可见性。

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

  def self.jurisdictions
    @@jurisdictions
  end
end

相关问题