【问题标题】:How to use Ruby mixins as patches to classes如何使用 Ruby mixin 作为类的补丁
【发布时间】:2012-04-13 06:39:31
【问题描述】:

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

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

【问题讨论】:

    标签: ruby metaprogramming mixins


    【解决方案1】:

    您的模块代码不起作用,因为它在错误的上下文中执行。您需要在A 的上下文中执行它,但它会在Plus 的上下文中进行评估。这意味着,您需要将 selfPlus 更改为 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"
    

    【讨论】:

      【解决方案2】:

      你不能以这种方式真正使用 Mixins。你在类和它的 mixin 之间产生了冲突。 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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-07
        • 1970-01-01
        • 2019-11-11
        • 2011-04-22
        • 1970-01-01
        相关资源
        最近更新 更多