2010-05-20 211 views
5

這怎麼能工作?訪問父類實例變量

class A 
    attr_accessor :name 

    def initialize params 
    @name = params[:name] 
    @collection << B.new 
    end 
end 

class B < A 
    def initialize 
    @my_name = lookup_something(<parent.name>) 
    end 
end 

基本上,我需要一個值從父類的子類中查找使用,但我不想明確地傳遞,如果有一個更好的辦法。父類的實例var在子類中完全無法訪問?或者這僅僅是糟糕的層次結構設計?

回答

8

我真的不知道你正在嘗試做的 - 所有的代碼,你發佈的作品上實例變量。實例變量是每個對象,而不是每個類,所以當你說「我需要父類的值」時,我不知道你的意思。

有幾件事情,我注意到你的代碼:

  • 基類應該永遠意識到子類。因此在A#initialize中創建B對象不是一件好事,因爲基礎使用子類。
  • 您將以與A#initialize完全不同的行爲覆蓋類B#initialize你甚至改變參數列表。不是一件好事。子類的對象的行爲方式應與其超類的對象相同。
  • 當您撥打B.new('myname')時,永遠不會分配變量@name,因爲永遠不會調用A#initialize方法。你將不得不要麼調用super(:name => name)(運行超initialize),或已分配給@name直接B#initialize
  • 一旦@name定義,所有的實例方法可以使用它的值。包括在父/超類中定義的那些。

讓我說我不太清楚爲什麼你在這裏使用繼承,我覺得這不是你想要的。如果你有兩個兩個班不同東西,應該有從來沒有被涉及的繼承。如果您想重新使用代碼,請查看Ruby的mixin功能,或者編寫具有您想要重用的行爲的幾個「較小」對象的複雜對象。

+0

很好的答案,除了一件事:改變子類的構造函數的簽名是完全正確的。這是因爲當你實例化時,你總是知道你正在處理的是什麼課。因此,構造函數不需要考慮多元模型。 (顯着的例外:您可能希望對構造,當你在做的元編程,或者你建立某種神奇的工廠相同/相似的界面。) – Franz 2016-08-03 09:45:51

+0

你是一種權利有關的構造特徵 - 它們是O.K.改變。這並不意味着擁有完全不同的基類和子類構造函數_behaviour_是很好的。 – averell 2016-08-23 09:53:24

2

你想要B繼承自A的原因是什麼?除非你有其他原因,否則設計這個的正確方法是簡單地將名稱作爲B的構造函數的參數,並丟棄繼承。

class A 
    attr_accessor :name 

    def initialize params 
    @name = params[:name] 
    @collection << B.new(@name) 
    end 
end 

class B 
    def initialize name 
    @my_name = lookup_something(@name) 
    end 
end 
2

約翰Nunemaker關於這個話題有一個不錯的article