前言:这是在Rails应用程序的上下文中。然而,问题是Ruby特有的。
假设我有一个Media
对象。
class Media < ActiveRecord::Base
end
我已将其扩展为几个子类:
class Image < Media
def show
# logic
end
end
class Video < Media
def show
# logic
end
end
在Media
类中,我想从适当的子类调用show
的实现。因此,如果self
是Video
,则来自Media,它会调用Video的show方法。如果self
改为Image
,则会调用Image的show方法。
来自Java背景,突然出现的第一件事就是“在超类中创建一个抽象方法”。但是,我在几个地方(包括Stack Overflow)读过抽象方法不是在Ruby中处理这个问题的最佳方法。
考虑到这一点,我开始researching typecasting并发现这也是Java思维的遗留物,在处理Ruby时我需要消除这种想法。
打败了,我开始编写看起来像这样的东西:
def superclass_method
# logic
this_media = self.type.constantize.find(self.id)
this_media.show
end
我已经在Ruby / Rails编写了一段时间了,但由于这是我第一次尝试这种行为并且现有资源没有直接回答我的问题,我希望得到更多经验丰富的开发人员的反馈意见如何完成我的任务。
那么,如何从Rails中的超类调用子类的方法实现?有没有比我最终(几乎)实现更好的方法?
答案 0 :(得分:22)
好问题,但是你太复杂了。请记住一些原则,一切都应该清楚......
这些类型将动态解析,因此如果对象的类层次结构中的show
存在 where ,那么它实际上是然后Ruby会找到并调用它。欢迎您输入对将来可能存在或不存在的任何内容的方法调用,它是合法的ruby语法,它将解析。您可以输入包含对this_will_never_be_implemented
的引用的表达式,除非实际调用它,否则没有人会关心。
即使在Java中,也只有一个实际对象。是的,你可能在超类中有一个调用方法的方法,但它是派生类的一个实例(以及基类的一个实例),所以你可以指望新的show
被调用。
从某种意义上说,每个Ruby类都是一个抽象类,包含可能在将来定义的每种可能方法的存根。您可以在基类或派生类中调用没有访问限定符的任何内容。
如果你想要一个null超类实现,你可能想要定义一个不做任何事情或引发异常的实现。
更新:可能我应该像其他任何方法一样“跟show
打电话”并将其留在那里,但是到目前为止我想补充一下:你也可以使用Ruby的多重继承版本实现show
:包含 SomeModule 。由于您显然对Ruby的对象模型感兴趣,因此您可以使用mixin实现您的属性,只是为了好玩。
答案 1 :(得分:10)
如你所知,让超类了解子类功能是一个很大的禁忌,这就是你想要抽象方法的原因。
您要做的是在超类中定义show
。然后你可以在超类中调用它,子类将调用它自己的版本,但是超类不会抛出错误。
class Media < ActiveRecord::Base
def show
# This method should be overloaded in a subclass
puts "Called from Media"
end
def do_something
show
end
end
class Image < Media
def show
puts "Called from Image"
end
end
class Video < Media
def show
puts "Called from Video"
end
end
i = Image.new
i.do_something
=> Called from Image
v = Video.new
v.do_something
=> Called from Video
答案 2 :(得分:2)
如果您想在show
的方法中拨打self
Media
,请执行此操作。但是,请确保self
响应方法调用。
class Media < ActiveRecord::Base
def foo
if self.respond_to?(:show)
self.show
else
... // *
end
end
...
end
要避免分支,请在媒体上实施show
,使用*作为show
的正文
class Media < ActiveRecord::Base
def foo
self.show
end
def show
...
end
end
答案 3 :(得分:2)
简单的回答。 只需将其称为。 Ruby没有编译时检查,所以没有人抱怨show
上没有定义Media
。如果@example
是[{1}}的实例,那么对Image
的任何调用都将首先发送到@example.show
,无论它在何处。仅当Image#show
不存在时,该呼叫才会传递到Image#show
,即使该呼叫来自Media