2017-07-26 61 views
1

只是搞亂了Ruby,正在嘗試以下操作。我知道我可以用案例陳述來做到這一點,但是實現它的正確方法是什麼?在Ruby中反向(?)類繼承

我希望它能夠輸入

Animals.new.interact 

,並得到取決於動物正確的回覆是什麼。

目前,我得到一個答覆

You are a eagle 
Not defined ! 
(repl):9:in `fly' 
(repl):14:in `interact' 
(repl):1:in `<main>' 

但我希望類似的規定(如果樣品是企鵝例如)

You are a penguin 
you cannot fly ! 

讚賞任何想法。

class Animals 
    SPECIES = [] 
    attr_accessor :name 
    def initialize 
    @name = SPECIES.sample 
    end 

def fly 
raise "Not defined !" 
end 

def interact 
puts "You are #{self}" 
fly 
end 

    def to_s 
    "a #{@name}" 
    end 

end 

class Penguin < Animals 

    def initialize 
    @name = "penguin" 
    SPECIES << @name 
    end 

    def fly 
    puts "you cannot fly !" 
    end 

end 

class Eagle < Animals 

    def initialize 
    @name = "eagle" 
     SPECIES << @name 

    end 

    def fly 
    puts "you fly high up the mountains !" 
    end 
end 
Penguin.new 
Eagle.new 
+3

這似乎是一個小的事情,但做竭盡全力,讓您的縮進一致性和正確性。當在這裏閱讀問題時,每一刻花費在試圖弄清楚你的代碼意味着什麼是花時間不回答問題。 – tadman

回答

0

你絕對沒有理解類。你爲什麼期望通過改變一個實例變量來改變對象的行爲?

當你做Animals.new你請求一個新的動物。和動物的行爲完全就像你在動物類,在其中定義的fly方法定義爲:

def fly 
raise "Not defined !" 
end 

所以這是絕對沒有理由期望you cannot fly !


你可以做這樣的事情,但是:

SPECIES = [] 
class Animals 
    attr_accessor :name 
    def initialize 
    @name = SPECIES.sample 
    end 

    def fly 
    raise "Not defined !" 
    end 

    def interact 
    puts "You are #{self}" 
    fly 
    end 

    def to_s 
    "a #{@name}" 
    end 

end 

class Penguin < Animals 
    SPECIES << self 

    def initialize 
    @name = "penguin" 
    end 

    def fly 
    puts "you cannot fly !" 
    end 
end 

class Eagle < Animals 
    SPECIES << self 

    def initialize 
    @name = "eagle" 
    end 

    def fly 
    puts "you fly high up the mountains !" 
    end 
end 

SPECIES.sample.new.interact 

現在SPECIES變量,我做了全球存儲不同動物的子類。當你致電SPECIES.sample你會得到一個像企鵝或鷹類。你實例化這個類,即你得到一個企鵝的實例,它的行爲與企鵝完全一樣,並且它是否可以飛行也是正確的。

+0

將它推廣到一個全局變量正在使得它變得更加混亂。它包含在父類中是有原因的。 – tadman

+1

@tadman你是對的。我的回答遠不及你的美麗。我投了你的答案!可悲的是,OP剛剛接受了我的回答。 – idmean

+0

你很快就會回答,而且它很有用,所以我猜想有人很熱!感謝您的支持。 – tadman

2

雖然你已經對子類和重寫方法有了正確的想法,但這裏的錯誤是,你的設計需要你在父類中出現之前實例化Animals實例,這是定義這些事物的一種非常不尋常的方式。你也在修改什麼應該是一個常量,這是一種糟糕的形式,而你的初始化方法只是填充名字,它不會選擇適當的類型。

在Ruby中,當你的initialize方法被調用時,你的對象被鎖定在一個無法改變的特定類型中。如果你想發射各種類型的動物,那麼你需要將它們存儲在已經預先構建的陣列中。

時,你的基類用於繼承通過定義inherited方法您可以隨時請求通知:

class Animals 
    def self.random 
    @types and @types.sample.new 
    end 
end 

class Animals 
    def self.inherited(subclass) 
    (@types ||= [ ]) << subclass 
    end 
end 

這允許您使用工廠方法隨機選擇一項

這簡化了其他實例的實現,並且不要求您做任何特殊的事情來讓它們正確鏈接:

class Penguin < Animals 
    def initialize 
    @name = "penguin" 
    end 

    def fly 
    puts "you cannot fly !" 
    end 
end 

class Eagle < Animals 
    def initialize 
    @name = "eagle" 
    end 

    def fly 
    puts "you fly high up the mountains !" 
    end 
end 

所以,當你調用工廠方法,你應該得到一個隨機的動物如:

Animals.random 
# => #<Eagle:0x007fc8f4109090 @name="eagle"> 
0

首先,對爲什麼它不工作的話題。

Class#new總是返回新分配的實例,不管你最後的語句是什麼,返回語句等。因此,你將得到一個非特定的AnimalAnimal.new


其次,如何「正常」做到這一點。

一個知道他所有孩子的課程是一個OO wtf時刻。相反,創建一個單獨的服務採摘動物:

module AnimalPicker 
    ANIMALS = [Penguin, Eagle] 

    def self.random 
    ANIMALS.sample.new 
    end 
end 

AnimalPicker.random 

第三,「但我真的想這樣做,這樣!!!! 1111!」

你可以重新定義Animal#new

class Animal 
    def self.new 
    [Penguin, Eagle].sample.new 
    end 
end 

Animal.new