3

我开始研究 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,因为我想“修补”几个具有相同行为的类。

有可能做我想做的事吗?如果是,如何?

4

2 回答 2

5

您的模块代码不起作用,因为它在错误的上下文中执行。您需要在 的上下文中执行它A,但它会在 的上下文中进行评估Plus。这意味着,您需要从self更改PlusA

观察:

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"
于 2012-04-13T06:48:14.423 回答
1

You can't really use Mixins in this way. You're generating a conflict between the class and its mixin. Mixins implicitly resolve the conflict by linearization. Bottom line is: In case of conflict, the class's method is preferred over the mixin. To fix that, you can use Sergio' Tulentsev's approach and have the mixin change its base class aggressively.

Or, you can add methods reflectively. Consider this example, which I've stolen from 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
于 2012-04-13T06:53:33.627 回答