我有使用super
的方法:
class A
def say txt
puts "A.say from #{self}: #{txt}"
end
def run
puts "A.run from #{self}: I am preparing something here..."
end
end
class B < A
def run
super
say 'I am B, adding 1'
say 'I am B, adding 2'
end
end
class C < A
def run
super
say 'I am C, adding 3'
say 'I am C, adding 4'
end
end
class D < C
def run
super
say 'I am D, adding 5'
end
end
我想从子类中删除super
,并想出了这个:
class A
def say txt
puts "A.say from #{self}: #{txt}"
end
def run
puts "A.run from #{self}: I am preparing something here..."
run_sub
end
def run_sub
# do nothing by default
end
end
class B < A
def run_sub
say 'I am B, adding 1'
say 'I am B, adding 2'
end
end
class C < A
def run_sub
say 'I am C, adding 3'
say 'I am C, adding 4'
run_sub_sub
end
def run_sub_sub
# do nothing by default
end
end
class D < C
def run_sub_sub
say 'I am D, adding 5'
end
end
只有叶类真正受益于此。因此,我想到将 run 方法的代码保留为 block ,并尝试按类层次结构的顺序调用它们。代码如下:
class A
def say txt
puts "A.say from #{self}: #{txt}"
end
def self.run &block
@run_block = block
end
def self.all_run_blocks
if self == A
return [@run_block]
else
return superclass.all_run_blocks + [@run_block]
end
end
run do
puts "A.run from #{self}: I am preparing something here..."
end
def run_all
self.class.all_run_blocks.each do |block|
block.call unless block.nil?
end
end
end
class B < A
run do
say 'I am B, adding 1'
say 'I am B, adding 2'
end
end
class C < A
run do
say 'I am C, adding 3'
say 'I am C, adding 4'
end
end
class D < C
run do
say 'I am D, adding 5'
end
end
b = B.new
d = D.new
b.run_all
d.run_all
但这不起作用,因为传递给 run
类方法的 block 保留在类的范围内,因此不知道 say
实例方法。
有没有更好的方法来实现这样的目标?
最佳答案
首先我想说这是一个非常有趣的问题,如果可以的话我会再次投票。感谢您提出一个实际上需要一些思考和努力的问题,我希望我的回答能够满足您的要求。
注意:我使用了您的明确示例,因此此方法不接受参数。处理参数也需要一些额外的工作。
为什么不将其设为模块
,这样您就可以在任何地方使用它?
module Appendable
def self.extended(base)
base.include(InstanceMethods)
end
def append_method(method_name,&block)
alias_name = create_alias(method_name)
define_method(method_name) do
run_callbacks(self,alias_name) do |object|
object.instance_eval &block
end
end
end
module InstanceMethods
def run_callbacks(object,method_name)
object.send(method_name)
yield(self)
end
end
private
def create_alias(method_name)
alias_name = "_#{method_name}_callback_#{self.name}"
alias_method alias_name, method_name
alias_name
end
end
它的作用只是将原始方法(在本例中是run
)方法别名为_METHODNAME_callback_CLASSNAME
,然后重新定义原始方法以首先调用别名版本,这会创建一个沿着链向上递归,然后返回到类中给出的 block 。
然后你只需像这样定义类:
class A
extend Appendable
def run
say "A"
end
def say(txt)
# I used puts to make it evident that it ran up the chain
puts "#{self.class.name} said #{txt}"
end
end
class B < A
append_method :run do
say "B"
end
end
class C < B
append_method :run do
say "C"
end
end
class D < A
append_method :run do
say "D"
end
end
class E < A
def run
puts "E overwrote run"
end
end
class F < E;append_method(:run) { say "F" }; end
这将允许您的所有类继承以前的分层方法,例如
A.new.run
A said A
B.new.run
B said A
B said B
C.new.run
C said A
C said B
C said C
D.new.run
D said A
D said D
F.new.run
E overwrote run
F said F
这似乎是您正在寻找的整体效果,除非我误解了?
关于ruby - 通过类层次结构进行链接,无需调用 `super` 或发明新名称,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30657147/