2011-07-22 102 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