我开始研究Ruby,因为我正在寻找一种更加动态的Java替代品。 我喜欢在定义之后如何修改Ruby中的类,例如:
class A
def print
"A"
end
end
class B < A
def print
super + "B"
end
end
class A
alias_method :print_orig, :print
def print
print_orig + "+"
end
end
puts B.new.print # A+B
现在我尝试用mixins做同样的事情:
class A
def print
"A"
end
end
class B < A
def print
super + "B"
end
end
module Plus
alias_method :print_orig, :print
def print
print_orig + "+"
end
end
A.extend(Plus) # variant 1
B.extend(Plus) # variant 2
class A # variant 3
include Plus
end
class B # variant 4
include Plus
end
puts B.new.print
然而,没有一种变体产生预期的结果。顺便说一下,预期结果如下:我希望能够用mixin“修补”A类,以便修改它的行为。我想使用mixins,因为我想用相同的行为“修补”几个类。
有可能做我想要的吗?如果是,怎么样?
答案 0 :(得分:5)
您的模块代码不起作用,因为它在错误的上下文中执行。您需要在A
的上下文中执行它,但它会在Plus
的上下文中进行评估。这意味着,您需要将self
从Plus
更改为A
。
观察:
class A
def print
"A"
end
end
class B < A
def print
super + "B"
end
end
module Plus
self # => Plus
def self.included base
self # => Plus
base # => A
base.class_eval do
self # => A
alias_method :print_orig, :print
def print
print_orig + "+"
end
end
end
end
A.send :include, Plus
B.new.print # => "A+B"
答案 1 :(得分:1)
你不能以这种方式真正使用Mixins。你在课堂和混音之间产生了冲突。 Mixins implicitly resolve the conflict by linearization.底线是:如果发生冲突,该类的方法优于mixin。要解决此问题,您可以使用Sergio' Tulentsev's approach and have the mixin change its base class aggressively。
或者,您可以反射性地添加方法。考虑这个我从Mark's blog偷来的例子。
class Talker
[:hello, :good_bye].each do |arg|
method_name = ("say_" + arg.to_s).to_sym
send :define_method, method_name do
puts arg
end
end
end
t = Talker.new
t.say_hello
t.say_good_bye