如何强制子类在Ruby中实现方法。在Ruby中似乎没有一个抽象关键字,这是我在Java中采用的方法。还有另外一种类似Ruby的方法来强制抽象吗?
在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.
但是,它似乎很少有必要。
我喜欢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
方法,因为它不知道它应该何时完成。如果您是程序员,那么您可以在此时对其进行测试。
我喜欢的方法类似但略有不同......我更喜欢它,如下所示,因为它使代码自我记录,给你一些非常类似于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
字符串常量?!?
我喜欢使用像abstract_method这样的宝石,它提供了一种dsl rails风格的语法抽象方法:
class AbstractClass
abstract_method :foo
end
class AbstractModule
abstract_method :bar
end
class ConcreteClass < AbstractClass
def foo
42
end
end
如果未在继承的类中定义方法'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
如果要在创建类的实例时抛出错误,可以执行以下操作
class AbstractClass
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