37

我正在实现一个包含集合的硬编码下拉列表的表单,我想知道最好的解决方案是什么,我知道下面公开的两种方式,但我仍然执行以下操作:

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

4 回答 4

36

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

于 2013-04-09T13:59:35.010 回答
36

TL; DR:这取决于。这些值是要在课堂外使用的吗?他们能变得有活力吗?他们可以更改子类吗?

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

更好的写法是:

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

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

这样写,方法和常量很相似。

一个关键的区别是,如果是子类,则细化方法会比常量Example更自然:optionsOPTIONS

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::OPTIONSandOPTIONS并不总是相同的,而self.optionsandoptions是相同的。通常在不指定范围的情况下使用常量(例如OPTIONS,而不是self::OPTIONS),并且在这种情况下继承将根本不起作用。

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

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

于 2013-04-09T16:48:59.787 回答
8

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

class Player
  JURISDICTIONS = %i(de uk ru)

  def self.jurisdictions
    JURISDICTIONS
  end
end

它有几个优点:

  • 它提供了一个干净的接口,封装了一个常量(你调用Player.jurisdictions而不是Player::JURISDICTIONS)。
  • 稍后只需更改方法即可添加其他逻辑。
  • The method can be stubbed in tests.

IMHO, performance does not matter here.

Update: Constant can bee hidden using private_constant method (http://ruby-doc.org/core-2.3.0/Module.html#method-i-private_constant)

于 2015-10-01T08:33:42.687 回答
2

To further refine Artur's suggestion I would go with a class variable in order to hide visibility of the constant.

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

  def self.jurisdictions
    @@jurisdictions
  end
end
于 2015-10-16T19:18:28.947 回答