module Imodule
???
end
class Some
include Imodule
def self.imethod
puts "original"
end
end
Some.imethod
# => "overrided"
如何创建一个覆盖静态方法的模块?
这是一道深入理解ruby特性的面试题。不要提出问题的另一种表述:)
最佳答案
好的,这是一个工作代码。请注意,您甚至不必触摸目标类! :)
class Klass
def self.say
puts 'class'
end
end
module FooModule
def self.included base
base.instance_eval do
def say
puts "module"
end
end
end
end
Klass.send(:include, FooModule)
Klass.say
解释
现在混合类方法的经典方式是这样(当然,它不能解决问题)。
module FooModule
def self.included base
base.extend ClassMethods
end
module ClassMethods
def bar
puts "module"
end
end
end
class Klass
include FooModule
def self.bar
puts 'class'
end
end
Klass.bar #=> class
当模块被包含或扩展到一个类中时,它的方法在继承链中位于该类方法的正上方。这意味着如果我们在该类方法中调用 super
,它将打印“module”。但我们不想触及原始类定义,我们想从外部更改它。
那么,我们可以做点什么吗?
对我们有好处,ruby 有一个概念 "open classes" .这意味着我们几乎可以更改应用程序中的所有内容,甚至是一些第 3 方库。每个类都可以“打开”,可以向其中添加新方法,也可以重新定义旧方法。让我们看看它是如何工作的。
class Klass
def self.bar
puts 'class'
end
end
class Klass
def self.bar
puts 'class 2'
end
end
Klass.bar #=> class 2
第二类定义不会覆盖前一个,它会打开并更改它。在这种情况下,恰好定义了一个同名的方法。这导致旧方法被新方法覆盖。这适用于任何类,甚至是基础库类。
puts [1, 2, 3].to_s #=> [1, 2, 3]
class Array
def to_s
"an array: #{join ', '}"
end
end
puts [1, 2, 3].to_s #=> an array: 1, 2, 3
或者同样的代码可以重写为
puts [1, 2, 3].to_s #=> [1, 2, 3]
Array.class_eval do
def to_s
"an array: #{join ', '}"
end
end
puts [1, 2, 3].to_s #=> an array: 1, 2, 3
应用知识
让我们从更简单的事情开始,比如覆盖实例方法。
class Klass
def say
puts 'class'
end
end
module FooModule
def self.included base
base.class_eval do
def say
puts "module"
end
end
end
end
Klass.send(:include, FooModule)
Klass.new.say #=> module
模块有一个特殊的回调函数,每次在类中包含一个模块时都会调用该回调函数。我们可以使用它来调用该类的 class_eval 并重新定义一个方法。
以类似的方式替换类方法。
class Klass
def self.say
puts 'class'
end
end
module FooModule
def self.included base
base.instance_eval do
def say
puts "module"
end
end
end
end
Klass.send(:include, FooModule)
Klass.say #=> module
这里唯一的区别是我们调用 instance_eval 而不是 class_eval。这可能是一个非常困惑的部分。简而言之,class_eval 创建实例方法,instance_eval 创建类方法。
这取 self 的 blog post .
关于ruby - 如何在 Ruby 中使用模块覆盖静态类方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9128515/