通过混合模块来覆盖类的实例方法

时间:2012-08-21 15:10:04

标签: ruby module override mixins

给定A类和B模块,混合B的实例方法,使其覆盖A的相应实例方法。

module B
  def method1
    "B\#method1"
  end

  def method2
    "B\#method2"
  end
end

class A
  def method1
    "A\#method1"
  end

  def method2
    "A\#method2"
  end

  # include B    does not override instance methods!
  #              (module gets mixed into the superclass)
end

puts A.new.method1   # want it to print out "B#method1"
puts A.new.method2   # want it to print out "B#method2"

2 个答案:

答案 0 :(得分:7)

Module#include将模块M作为类C超类插入。因此,您无法覆盖C中的M方法,而是相反:C的方法会覆盖M的方法。 (从技术上讲,Ruby不会使M成为C的超类,而是创建一个不可见的包含类 ⟦M′⟧,其方法表和常量表指向M的方法表和常量表,并使那个类成为超类,但这种区别对于这个特定的问题并不重要。)

在Ruby 2.0中,有一种新方法Module#prepend,正如其名称所示,预先 MC的祖先,换句话说,使M成为C子类

所以,简而言之:你不能,至少现在还没有。

答案 1 :(得分:0)

在加入B之前,您可以从A删除B个方法。

class A
  def method1
    "A\#method1"
  end

  def method2
    "A\#method2"
  end

  B.instance_methods(false).each { |method|
    remove_method(method) if instance_methods(false).include?(method)
  }
  include B
end

或者来自B

module B
  def method1
    "B\#method1"
  end

  def method2
    "B\#method2"
  end

  def self.append_features(mod)
    instance_methods(false).each { |method|
      mod.send(:remove_method, method) if mod.instance_methods(false).include?(method)
    }
    super
  end
end