如何在ruby中实现抽象类?
我知道ruby中没有抽象类的概念。但如果真的需要实施的话,该怎么做呢?我尝试了一些像如何在ruby中实现抽象类?,ruby,abstract-class,Ruby,Abstract Class,我知道ruby中没有抽象类的概念。但如果真的需要实施的话,该怎么做呢?我尝试了一些像 class A def self.new raise 'Doh! You are trying to write Java in Ruby!' end end class B < A ... ... end A类 def self.new 举起手来!您正在尝试用Ruby编写Java 结束 结束 B类
class A
def self.new
raise 'Doh! You are trying to write Java in Ruby!'
end
end
class B < A
...
...
end
A类
def self.new
举起手来!您正在尝试用Ruby编写Java
结束
结束
B类
但是当我尝试实例化B时,它将在内部调用A.new
,这将引发异常
此外,模块不能实例化,但也不能继承。将新方法私有化也不起作用。有什么指针吗?我个人提出了抽象类方法中的NotImplementedError。但是,出于您提到的原因,您可能希望将其排除在“new”方法之外。我不喜欢在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
模块摘要
def抽象_方法(*args)
args.each do| name|
class_eval(你的方法没有问题。在初始化中引发一个错误似乎很好,当然,只要你的所有子类都覆盖了initialize。但是你不想这样定义self.new。下面是我要做的
class A
class AbstractClassInstiationError < RuntimeError; end
def initialize
raise AbstractClassInstiationError, "Cannot instantiate this class directly, etc..."
end
end
A类
类AbstractClassInstallionError
另一种方法是将所有这些功能放在一个模块中,正如您所提到的,这是永远无法灌输的。然后将该模块包含在您的类中,而不是从另一个类继承。但是,这会破坏类似super的功能
因此,这取决于您想要如何构造它。虽然模块似乎是解决“如何编写一些专为其他类使用的东西”问题的更干净的解决方案,但请尝试以下方法:
class A
def initialize
raise 'Doh! You are trying to instantiate an abstract class!'
end
end
class B < A
def initialize
end
end
A类
def初始化
提出“Doh!您正试图实例化一个抽象类!”
结束
结束
B类
如果要使用不可实例化的类,请在抛出错误之前,在A.new方法中检查self==A
但实际上,模块看起来更像您在这里想要的东西-例如,Enumerable是一种在其他语言中可能是抽象类的东西。从技术上讲,您不能对它们进行子类化,但是调用include SomeModule
实现了大致相同的目标。这对您不起作用有什么原因吗?您尝试的目的是什么使用抽象类服务吗?在ruby中可能有更好的方法,但您没有给出任何细节
我的指针是这样的;请使用not继承。另一个答案:
module Abstract
def self.append_features(klass)
# access an object's copy of its class's methods & such
metaclass = lambda { |obj| class << obj; self ; end }
metaclass[klass].instance_eval do
old_new = instance_method(:new)
undef_method :new
define_method(:inherited) do |subklass|
metaclass[subklass].instance_eval do
define_method(:new, old_new)
end
end
end
end
end
模块摘要
定义自我附加功能(klass)
#访问对象的类方法副本&例如
元类=lambda{| obj |类#
A.new#raises#在最近6年半的Ruby编程中,我一次也不需要抽象类
如果您认为您需要一个抽象类,那么您在提供/需要抽象类的语言中考虑的太多了,而不是在Ruby中
正如其他人所建议的,MIXIN更适合于那些被认为是接口的东西(如java定义的),并且重新设计你的设计更适合于“需要”C++等其他语言的抽象类。
2019年更新:我已经16年半没有需要Ruby中的抽象类了。所有对我的回答发表评论的人所说的一切都是通过实际学习Ruby和使用适当的工具来解决的,比如模块(甚至给你提供了通用的实现).在我管理的团队中,有人创建了一些基本实现失败的类(比如抽象类),但这些大多是对编码的浪费,因为
NoMethodError
会产生与生产中的AbstractClassError
完全相同的结果。a类
class A
private_class_method :new
end
class B < A
public_class_method :new
end
私有类方法:新
结束
B类
我想稍后再插话,我认为没有理由阻止某人实例化抽象类
Duck类型语言,如Ruby,在运行时使用方法的存在/不存在或行为来确定是否应该调用它们。因此,当您的问题应用于抽象的方法时,它是有意义的
def get_db_name
raise 'this method should be overriden and return the db name'
end
这应该是故事的结尾。在Java中使用抽象类的唯一原因是坚持某些方法“填充”,而其他方法的行为在抽象类中。在duck类型语言中,重点是方法,而不是类/类型,因此您应该将您的担忧转移到这一级别
在您的问题中,您基本上是试图从Java中重新创建abstract
关键字,这是在Ruby中执行Java的代码味道。我是这样做的,因此它重新定义了new on child类,以找到一个新的on非抽象类。
我仍然看不到在ruby中使用抽象类的任何实用性
puts 'test inheritance'
module Abstract
def new
throw 'abstract!'
end
def inherited(child)
@abstract = true
puts 'inherited'
non_abstract_parent = self.superclass;
while non_abstract_parent.instance_eval {@abstract}
non_abstract_parent = non_abstract_parent.superclass
end
puts "Non abstract superclass is #{non_abstract_parent}"
(class << child;self;end).instance_eval do
define_method :new, non_abstract_parent.method('new')
# # Or this can be done in this style:
# define_method :new do |*args,&block|
# non_abstract_parent.method('new').unbind.bind(self).call(*args,&block)
# end
end
end
end
class AbstractParent
extend Abstract
def initialize
puts 'parent initializer'
end
end
class Child < AbstractParent
def initialize
puts 'child initializer'
super
end
end
# AbstractParent.new
puts Child.new
class AbstractChild < AbstractParent
extend Abstract
end
class Child2 < AbstractChild
end
puts Child2.new
放置“测试继承”
模块摘要
def新
抛出“摘要!”
结束
def继承(儿童)
@抽象=真
“继承的”
非抽象父类=self.superclass;
而非_abstract_parent.instance_eval{@abstract}
非抽象父类=非抽象父类
结束
放置“非抽象超类为#{Non_abstract_parent}”
(class2行宝石:你可以试试3个宝石:
我的2倍:我选择了一款简单、轻便的DSL混音器:
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
模块摘要
扩展ActiveSupport::关注点
包括做
#接口,用于声明性地指示要创建一个或多个方法
#作为抽象方法处理,仅在子类中实现。
#
#论据:
#-方法(符号或数组)待处理的方法名称列表
#抽象基础
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
class Foo
include AbstractType
# Declare abstract instance method
abstract_method :bar
# Declare abstract singleton method
abstract_singleton_method :baz
end
Foo.new # raises NotImplementedError: Foo is an abstract type
Foo.baz # raises NotImplementedError: Foo.baz is not implemented
# Subclassing to allow instantiation
class Baz < Foo; end
object = Baz.new
object.bar # raises NotImplementedError: Baz#bar is not implemented
self.abstract_class = true
>> A.new
(rib):2:in `main'
(rib):2:in `new'
(rib):3:in `initialize'
RuntimeError: abstract class
>> B.new
initialized
=> #<B:0x00007f80620d8358>
>>