如何实施抽象类 ruby?

我知道 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

, 这会导致例外。

此外,模块无法通过副本创建,但它们也无法继承。 使新方法Privatat不起作用。 有些说明?
已邀请:

快网

赞同来自:

我认为没有理由阻止某人创建抽象类实例,
http://asqyzeron.wordpress.com ... time/
.

鸭肉套装语言如 Ruby, 使用存在/执行期间的方法的缺失或行为,以确定它们是否应被调用。 所以你的问题是因为它是指抽象

方法

, 有意思


def get_db_name
raise 'this method should be overriden and return the db name'
end


而且这个故事应该结束。 在java中使用抽象类的唯一原因在某些方法得到的事实上 "filled-in", 虽然其他人在抽象课上有他们的行为。 在鸭子集的语言中侧重于方法,而不是 classes/types,, 因此,您必须推迟您对此级别的疑虑。

在您的问题中,您主要尝试重新创建关键字
abstract

的 Java, 这是执行的闻名代码 Java 在 Ruby.

冰洋

赞同来自:

我不喜欢在抽象课程中使用 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

快网

赞同来自:

对于世界上任何人 rails 销售模式 ActiveRecord 作为抽象类在模型文件中使用此广告执行:


self.abstract_class = true

三叔

赞同来自:

最后一个 6 1/2 多年的编程 Ruby 我从不

发布

抽象课程。

如果您认为您需要抽象类,则您认为提供给他们的语言太多/要求,不在 Ruby 因此。

作为其他,混合更适合必须是界面的东西。 /正如他们所确定的那样 Java/, 和你的设计的重新思考更适合那些事情 "need" 来自其他语言的抽象类,如 C++.

更新 2019: 我不需要抽象课程 Ruby 为了 16 半年的使用。 所有人都评论我的答案评论的所有这些都是通过实际学习解决的 Ruby 并使用模块等适当的工具 /甚至为您提供一般实施/. 在我管理的团队中,有些人创建了没有基本实现的课程 /例如,一个抽象类/, 但这基本上是浪费代码,因为
NoMethodError

将完全相同的结果
AbstractClassError

在生产中。

江南孤鹜

赞同来自:

我的 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


当然,在这种情况下,添加另一个初始化基本类的错误将是微不足道的。

帅驴

赞同来自:

就个人而言,我提出 NotImplementedError 在抽象课程的方法中。 但是你可以把它留在方法之外。 'new' 出于你提到的原因。

郭文康

赞同来自:

如果您想在您的方法中使用卸载的类 A.new 检查是否有 self == A, 在发出错误之前。

但实际上,模块更像是你需要的东西 — 例如,枚举是可以成为其他语言的抽象类的东西。 从技术上讲,你不能将它们归类,但挑战
include SomeModule

达到同样的目的。 没有任何理由为什么它不适合你?

裸奔

赞同来自:

你想和一个抽象班服务的目标是什么? 可能有更好的方法来做到 ruby, 但你没有提供任何细节。

我的指针是:使用
http://www.rubycentral.com/pic ... .html
, 不是继承。

董宝中

赞同来自:

我以这种方式做到了,所以他重新定义 new on child class, 寻找新的 on non abstract class.
我仍然没有看到使用抽象课程的任何实际好处 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

冰洋

赞同来自:

另一个答案:


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


这取决于通常的 #method_missing 报告未实现的方法,
但不允许实施抽象课程 /即使他们有一种方法 initialize/


class A
include Abstract
end
class B < A
end

B.new #=> #<b:0x24ea0>
A.new # raises #<nomethoderror: `new'="" a:class="" for="" method="" undefined="">


像其他海报一样,您可能必须使用Mixin,而不是抽象类。
</nomethoderror:></b:0x24ea0>

窦买办

赞同来自:

还有这个小
abstract_type

gem, 允许不引人注目地声明抽象类和模块。

例子 /从文件。 README.md/:


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

知食

赞同来自:

你的方法没有错。 造成错误 initialize 似乎是正常的,如果当然,你的所有子类覆盖 initialize. 但你不想确定 self.new 因此。 这就是我会做的。


class A
class AbstractClassInstiationError < RuntimeError; end
def initialize
raise AbstractClassInstiationError, "Cannot instantiate this class directly, etc..."
end
end


另一种方法是将您提到的模块中的所有这些功能放在您所提到的模块中,永远不会被激怒。 然后将模块打开到您的类中,而不是从另一个类继承它。 但是,它会使超级的东西打破这样的东西。

所以这一切都取决于你想如何训练它。 虽然模块似乎是解决问题的更清洁的解决方案 "我怎样才能写一些辩叉使用其他课程的东西"

窦买办

赞同来自:

虽然它看起来不像 Ruby, 你能行的:


class A
def initialize
raise 'abstract class' if self.instance_of?/A/

puts 'initialized'
end
end

class B < A
end


结果:


>> A.new
/rib/:2:in `main'
/rib/:2:in `new'
/rib/:3:in `initialize'
RuntimeError: abstract class
>> B.new
initialized
=> #<b:0x00007f80620d8358>
&gt;&gt;


</b:0x00007f80620d8358>

要回复问题请先登录注册