Ruby如何使用Module覆盖类方法

方法一:用instance_eval。原文中的方法。

module BooModule
  def self.included base
    base.instance_eval do
      def bar
        puts "module"
      end
    end
  end
end

class KlassC

  def self.bar
    puts 'class'
  end
end

KlassC.send(:include, BooModule)

KlassC.bar #=> module
p KlassC.ancestors

方法二:用 class << base ; end

module TooModule
  def self.included base
    class << base
      def bar
        puts "module"
      end
    end
  end
end

class KlassD

  def self.bar
    puts 'class'
  end
end

KlassD.send(:include, TooModule)

KlassD.bar #=> module
p KlassD.ancestors

方法三:用prepend。如果你知道extend实际上就是class << base; include ClassMethods end的话,你就很好理解为啥prepend在这里可以起作用了。前两者都是直接修改类方法,而这直接通过修改继承链的方法去覆盖类方法。

module GooModule
  def self.included base
    class << base
      prepend ClassMethods
    end
  end

  module ClassMethods
    def bar
      puts "module"
    end
  end
end

class KlassE
  def self.bar
    puts 'class'
  end
end

KlassE.send(:include, GooModule)

KlassE.bar #=> module
p KlassE.ancestors

能够直接用prepend么?不行。你可以试试下面的例子。虽然说,被prepend的module会放到class的继承链的下方,但实际上,类方法却不受影响。


module FooModule
  def self.included base
    base.extend ClassMethods
  end

  def self.prepended base
    base.extend ClassMethods
  end

  module ClassMethods
    def bar
      puts "module"
    end
  end
end

class KlassA
  include FooModule

  def self.bar
    puts 'class'
  end
end


KlassA.bar #=> class
p KlassA.ancestors

class KlassB
  prepend FooModule

  def self.bar
    puts 'class'
  end
end


KlassB.bar #=> class
p KlassB.ancestors

 

转载需保留链接来源:软件玩家 » Ruby如何使用Module覆盖类方法

赞 (0)