2011-07-22 63 views
40

如何強制子類在Ruby中實現方法。 Ruby中似乎沒有抽象關鍵字,這是我在Java中採用的方法。是否還有另外一種類似Ruby的方法來強制抽象?Ruby中的抽象方法

+0

另外有一個錯誤拋出,紅寶石使用一種叫鴨打字: http://en.wikipedia.org/wiki/Duck_typing – mikeycgto

+7

@delnan,沒有必要像這樣說出你的答案。如果我試圖堅持Java思維模式,我不會要求「類似Ruby」的解決方案。然而,感謝您對運行時異常的建議。 –

+2

如果我粗魯無禮,我很抱歉。我剛剛看到*如此多*的人試圖用語言A進行編程,就好像它是語言B一樣。你問的問題看起來有點像這樣,因爲你問如何做Java中的抽象類(而不是「等價於抽象類的ruby」或類似於zhsz的東西)。再一次,沒有冒犯的意思,也許我錯了。 – delnan

回答

43

在Ruby中,抽象方法應該不太有用,因爲它不是 強烈的 靜態類型。

然而,這是我做的:

class AbstractThing 
    MESS = "SYSTEM ERROR: method missing" 

    def method_one; raise MESS; end 
    def method_two; raise MESS; end 
end 

class ConcreteThing < AbstractThing 
    def method_one 
    puts "hi" 
    end 
end 

a = ConcreteThing.new 
a.method_two # -> raises error. 

它很少似乎是必要的,但是。

+7

Ruby是強類型的。只是不是靜態類型。 –

+0

我總是弄錯了。 Ta,編輯。 – Andy

+1

+1,這就是在Smalltalk中通過'subclassResponsibility'('^ self subclassResponsibility')完成的。 –

7

我的首選的方法是類似的,但略有不同......我喜歡它,如下所示,因爲它使代碼自我記錄,讓您非常相似Smalltalk的東西:

class AbstractThing 
    def method_one; raise "SubclassResponsibility" ; end 
    def method_two; raise "SubclassResponsibility" ; end 
    def non_abstract_method; method_one || method_two ; end 
end 

有些人會抱怨這是少幹,並堅持創建一個異常子類和/或把"SubclassResponsibility"字符串在一個常量,但恕我直言you can dry things up to the point of being chafed, and that is not usually a good thing。例如。如果您的代碼庫中有多個抽象類,那麼您將在何處定義MESS字符串常量?!?

+0

如何用符號擊敗em :)然後它是一個常量,漂浮在四周,而不是每個情況下的字符串。喜歡你的答案。 – baash05

+0

唯一的反對意見是,子類將不得不實施no_abstract_method,否則當它被調用(大概是測試)時,方法一將被調用,方法2可能被調用。 – baash05

4

我喜歡像abstract_method使用的寶石。這給DSL鐵軌樣式語法抽象方法:

class AbstractClass 
    abstract_method :foo 
end 

class AbstractModule 
    abstract_method :bar 
end 

class ConcreteClass < AbstractClass 
    def foo 
    42 
    end 
end 
14

我喜歡pvandenberk答案,但如下我會改進:

module Canine  # in Ruby, abstract classes are known as modules 
    def bark 
    fail NotImplementedError, "A canine class must be able to #bark!" 
    end 
end 

現在,如果您創建了一個屬於Canine「抽象類」(即在其祖先中具有Canine模塊的類)的類,它將在發現#bark方法未實現時發出投訴:

class Dog 
    include Canine # make dog belong to Canine "abstract class" 
end 

Dog.new.bark  # complains about #bark not being implemented 

class Dog 
    def bark; "Bow wow!" end 
end 

# Now it's OK: 
Dog.new.bark #=> "Bow wow!" 

注意,因爲Ruby類不是靜態的,而是一直開到變化,Dog類本身不能強制執行的#bark方法存在,因爲當它應該是完成了它不知道。如果你是一名程序員,那麼在這個時候你需要測試它。

1

如果未在繼承的類中定義方法'foo','bar'和'mate',則此代碼不會讓您加載該類。

它沒有考慮跨許多文件定義的類,但讓我們誠實地做我們中的許多人實際上跨許多文件定義類方法?我的意思是如果你不計算混插。 (此可說明)

def self.abstract(*methods_array) 
    @@must_abstract ||= [] 
    @@must_abstract = Array(methods_array) 
end 
def self.inherited(child) 
    trace = TracePoint.new(:end) do |tp| 
     if tp.self == child #modules also trace end we only care about the class end 
     trace.disable 
     missing = (Array(@@must_abstract) - child.instance_methods(false)) 
     raise NotImplementedError, "#{child} must implement the following method(s) #{missing}" if missing.present? 
     end 
    end 
    trace.enable 
end 

abstract :foo 
abstract :bar, :mate 
0

如果你想在創建類的實例,你可以做以下

class AnstractClass 
    def self.new(args) 
    instance = allocate # make memory space for a new object 
    instance.send(:default_initialize, args) 
    instance.send(:initialize, args) 
    instance 
    end 

    #This is called whenever object created, regardless of whether 'initialize' is overridden 
    def default_initialize(args) 
    self.abstract_method #This will raise error upon object creation 
    end 
    private :default_initialize 

    def initialize(args) 
    # This can be overridden by new class 
    end 
end 


class NewClass < AbstractClass 
end 

NewClass.new #Throw error