2013-04-09 52 views
32

我正在實現一個表單,其中包含一個硬編碼的下拉集合,我想知道什麼是最好的解決方案,我知道這兩種方式暴露在工作之下,但我做了如下:Ruby/Rails中的類方法vs常量

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被調用。

問題是,這些都是好的方法,或者根本沒關係?

+0

普遍接受的做法是後者與註釋的大寫在前的文件的形式提供給用戶,這是一個恆定的 – 2013-04-09 13:56:15

+2

無關的一個可能的答案,我會建議使用過的字符串,除非你的代碼將專門符號需要字符串。因此'[:是,:否,:not_sure]' – 2013-04-09 14:01:29

回答

33

後者更好。如果它是一種方法,每次調用時都會創建一個新的數組和新的字符串,這會浪費資源。

+1

不錯!謝謝:) – 2013-04-09 14:03:22

+0

很棒,+10,如果可以的話;-) – 2013-04-09 14:04:22

+0

+1調用'Example.methods'會告訴options是一種方法,當你知道是一個類常量時。這是製作一致代碼的另一個技巧。 – nicooga 2013-04-09 14:43:15

26

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,以避免任何人修改它。

+0

你仍然可以用常量做類似的事情:'Example :: Options = [「Yes」,「No」,「Not sure」]; Parent :: Options = [* Example :: Options,「Extra」]'。唯一的區別是你必須顯式地編寫父類而不是使用'super'。 – sawa 2013-04-09 17:16:10

+2

@sawa:的確,你可以(你可以使用'superclass'而不是明確寫出父類),但訪問常量可能會非常棘手。編輯我的答案。 – 2013-04-09 17:27:46

+0

問題中的相關想法是直接調用常量,如「Example :: OPTIONS」或「Parent :: OPTIONS」或「OPTIONS」。我不明白你爲什麼要定義'self.foo'來調用它們。 – sawa 2013-04-09 17:41:34

6

我最常做的是有上述技術的混合:

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

+2

你有一個錯字它應該是自我。 – Sunny 2015-10-07 10:41:37

+0

謝謝!固定。 – 2015-10-07 15:56:18

1

要進一步細化阿圖爾的建議,我會用一個類變量去爲了隱藏不變的知名度蜜蜂隱藏。

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

    def self.jurisdictions 
    @@jurisdictions 
    end 
end 
+0

效果更好,贊同!但到目前爲止,我無法解決這裏描述的繼承問題:http://www.railstips.org/blog/archives/2006/11/18/class-and-instance-variables-in-ruby/ – 2015-12-04 09:03:27

+0

我寫這篇文章後我發現你還應該考慮類級別的實例變量:http://www.railstips.org/blog/archives/2006/11/18/class-and-instance-variables-in-ruby/ – 2015-12-23 17:10:25