2012-03-14 75 views
0

我發現我的自我重複的事情,當我在Ruby中創建類很多,我常常會落得類似下面的內容:在Ruby中定義類時避免重複?

class Foo 
    attr_reader :bar_0, 
       :bar_1, 
       . 
       . 
       . 
       :bar_n 
    def initialize(bar_0 = something, 
        bar_1 = something, 
         . 
         . 
         . 
        bar_n = something) 
    @bar_0 = bar_0 
    @bar_1 = bar_1 
      . 
      . 
      . 
    @bar_n = bar_n 
    end 
end 

是否紅寶石採用更有效地實施這樣的一條捷徑?

+0

你究竟想要做什麼?具有50個參數的構造函數在任何語言中都很難看。 – 2012-03-14 19:48:27

+0

這不是我想包括已經包含的東西,我只是希望能夠在類上調用new時定義實例變量('@bar = bar'),爲new設置默認值(bar =(無)),並使其可訪問('attr_reader'),而不必重複我自己三次 – rudolph9 2012-03-14 20:01:36

回答

1

從問題的表達方式來看,您應該重新考慮您的課程設計。但是,Ruby提供了一種有趣的方式來快速創建與attr_accessor(不是讀者)的類。這裏有一個簡單的例子:

>> class Person < Struct.new(:name, :age) ; end 
=> nil 
>> p = Person.new 
=> #<struct Person name=nil, age=nil> 
>> p.age = 23 
=> 23 
>> p.class 
=> Person 
>> p.methods.grep(/age/) 
=> [:age, :age=] 

當然,這是一個普通的類,你可以添加你想要的所有方法(和使用getter和setter方法,而不是實例變量,例如var的getter和self.var = foo的二傳手) 。

如果你真的不希望作家,使他們私人或undef他們。

>> attrs = [:name, :age] 
=> [:name, :age] 
>> class Person < Struct.new *attrs ; end 
=> nil 
>> Person.instance_eval { private *attrs.map{|attr| "#{attr}=" }} 
=> Person 
>> p = Person.new 
=> #<struct Person name=nil, age=nil> 
>> p.methods.grep(/age/) 
=> [:age] 

上述所有不隨當然initialize的萬噸任務的幫助,但後來人們不禁要問,如果你真的想許多構造函數的參數,或者,也許你只是有一個哈希參數和合併到這默認散列。

+0

我一直想知道天氣只是把所有的東西放在這麼多的構造函數變量的散列,但我想有任何一種方法的初始化可用。本質上,我正在編寫一個Gem來與REST API進行接口,並且我正在努力盡可能有利於它所包含的任何項目。具體來說,我希望從REST調用中提取的每個變量都可以通過'p = Foo.new(argument_0,...,argument_n)'和/或'p = Foo.new(hash)'獲得並且有任何參數可用通過'p.bar_i'。有點java的心態,但有用的不少。 – rudolph9 2012-03-15 06:04:33

0

Ruby是動態的,在內省方面提供了很多內容,因此您可以使用元編程(或編寫基本上編寫代碼的代碼)。在您的例子有幾件事情可以做,以清理冗長:

class Foo 
    # Rather than writing bar_1, bar_2, bar_3, ... 
    attr_accessor ((0..9).to_a + ('a'..'n').to_a).map { |x| :"foo_#{x}" } 

    # Using mass assignment... 
    def initialize(attributes = {}) 
    attributes.each do |attribute, value| 
     respond_to?(:"#{attribute}=") && send(:"#{attribute}=", value) 
    end 
    end 
end 

由於質量分配是一個普遍的和可重複使用的行爲,它是有道理的其解壓縮到一個單獨的模塊,使之成爲混入:

module MassAssignment 
    def initialize(attributes = {}) 
    mass_assign(attributes) 
    end 

    def mass_assign(attributes) 
    attributes.each do |attribute, value| 
     respond_to?(:"#{attribute}=") && send(:"#{attribute}=", value) 
    end 
    end 
end 

class Foo 
    include MassAssignment 
end 
+0

'attr_reader((0..9).to_a +('a'..'n').to_a).map { | X | :「foo _#{x}」}'我認爲這是WTF類型代碼的很酷的例子。 Ruby可以做到這一點,但我認爲它不應該被其他任何人看到的實時代碼使用。 – iafonov 2012-03-14 20:02:27

+1

不一定是bar_i實例變量的一致命名約定,我需要能夠設置默認值。我希望能夠在一個定義中完成我現在所做的三個單獨定義。 – rudolph9 2012-03-14 20:03:37

+1

在1.9中,你可以像這樣創建數組:'[* 0..9,*?a ..?n]'。 :-) – 2012-03-14 20:04:30