我知道ruby中没有抽象类的概念.但是,如果它需要实施,那该怎么办呢?我试过像......
class A def self.new raise 'Doh! You are trying to write Java in Ruby!' end end class B < A ... ... end
但是当我尝试实例化B时,它会在内部调用A.new
哪个会引发异常.
此外,模块无法实例化,但也无法继承.使新方法私有也行不通.有什么指针吗?
只是为了在这里编写,我认为没有理由阻止某人实例化抽象类,特别是因为他们可以动态添加方法.
鸭子类型语言(如Ruby)在运行时使用方法的存在/不存在或行为来确定是否应该调用它们.因此,您的问题,因为它适用于抽象方法,是有道理的
def get_db_name raise 'this method should be overriden and return the db name' end
这应该是关于故事的结尾.在Java中使用抽象类的唯一原因是坚持某些方法被"填充",而其他方法则在抽象类中使用它们的行为.在鸭子打字语言中,重点是方法,而不是类/类型,所以你应该把你的担忧转移到那个级别.
在你的问题中,你基本上是在尝试abstract
从Java 重新创建关键字,这是在Ruby中编写Java的代码味道.
我不喜欢在Ruby中使用抽象类(几乎总是有更好的方法).如果你真的认为它是最适合这种情况的技术,你可以使用下面的代码片段来更多地声明哪些方法是抽象的:
module Abstract def abstract_methods(*args) args.each do |name| class_eval(<<-END, __FILE__, __LINE__) def #{name}(*args) raise NotImplementedError.new("You must implement #{name}.") end END # important that this END is capitalized, since it marks the end of <<-END end end end require 'rubygems' require 'rspec' describe "abstract methods" do before(:each) do @klass = Class.new do extend Abstract abstract_methods :foo, :bar end end it "raises NoMethodError" do proc { @klass.new.foo }.should raise_error(NoMethodError) end it "can be overridden" do subclass = Class.new(@klass) do def foo :overridden end end subclass.new.foo.should == :overridden end end
基本上,您只需abstract_methods
使用抽象方法列表调用,当它们被抽象类的实例调用时,NotImplementedError
将引发异常.
试试这个:
class A def initialize raise 'Doh! You are trying to instantiate an abstract class!' end end class B < A def initialize end end
class A private_class_method :new end class B < A public_class_method :new end
我的2¢:我选择简单轻巧的DSL mixin:
module Abstract extend ActiveSupport::Concern included do # Interface for declaratively indicating that one or more methods are to be # treated as abstract methods, only to be implemented in child classes. # # Arguments: # - methods (Symbol or Array) list of method names to be treated as # abstract base methods # def self.abstract_methods(*methods) methods.each do |method_name| define_method method_name do raise NotImplementedError, 'This is an abstract base method. Implement in your subclass.' end end end end end # Usage: class AbstractBaseWidget include Abstract abstract_methods :widgetify end class SpecialWidget < AbstractBaseWidget end SpecialWidget.new.widgetify # <= raises NotImplementedError
当然,在这种情况下,为初始化基类添加另一个错误将是微不足道的.
对于rails世界中的任何人来说,在模型文件中使用此声明来实现ActiveRecord模型作为抽象类:
self.abstract_class = true
在编程Ruby的最后6年半里,我不需要一次抽象类.
如果您认为自己需要一个抽象类,那么您在提供/需要它的语言中会考虑太多,而不是在Ruby中.
正如其他人所建议的那样,mixin更适合于那些应该是接口的东西(正如Java定义的那样),重新思考你的设计更适合那些需要来自其他语言(如C++)的抽象类的东西.
更新2019:在使用16年半的时间里,我不需要Ruby中的抽象类.通过实际学习Ruby并使用适当的工具(如模块(甚至可以为您提供常见实现)),可以解决所有人对我的回复所做的评论.我管理的团队中有些人创建了基本实现失败的类(如抽象类),但这些人大多浪费编码,因为它NoMethodError
会产生与生产中完全相同的结果AbstractClassError
.
你可以尝试3个rubygems:
界面
抽象
简单的抽象