Ruby中如何克隆类并替换模块方法调用生成修改副本?
解决方案
要实现复制类并替换其中的模块方法调用,有几种可行的方式:
方法一:直接重写目标方法
如果方法逻辑不复杂,直接在复制后的Meouw类里重新定义call方法,把Foo.check替换成Bar.check即可:
module Foo def self.check "foo" end end module Bar def self.check "bar" end end class Bark def call puts Foo.check end end Bark.new.call # => 输出 "foo" Meouw = Bark.dup # 重写call方法 class Meouw def call puts Bar.check end end Meouw.new.call # => 输出 "bar"
方法二:动态修改方法源码
如果原方法逻辑复杂,不想重复编写代码,可以通过读取原方法的源码字符串,替换目标模块名后重新定义:
module Foo def self.check "foo" end end module Bar def self.check "bar" end end class Bark def call puts Foo.check end end Bark.new.call # => 输出 "foo" Meouw = Bark.dup # 获取原方法的源码并替换模块名 original_source = Bark.instance_method(:call).source modified_source = original_source.gsub("Foo.check", "Bar.check") # 在Meouw类中执行修改后的代码 Meouw.class_eval(modified_source) Meouw.new.call # => 输出 "bar"
注意:这种方式依赖于Ruby的source方法(需要Ruby 2.1+,且代码必须在可读取源码的环境下运行,比如irb或本地文件,不适用于已编译的二进制代码)。
方法三:利用模块混入(更灵活的设计思路)
如果后续可能需要频繁切换这类模块调用,建议一开始就把依赖的模块设计成可注入的,避免后期修改类的麻烦:
module Foo def self.check "foo" end end module Bar def self.check "bar" end end class Bark attr_accessor :check_module def initialize(check_module: Foo) @check_module = check_module end def call puts check_module.check end end Bark.new.call # => 输出 "foo" # 不需要复制类,直接传入不同模块即可 Meouw = Bark.dup Meouw.new(check_module: Bar).call # => 输出 "bar" # 甚至不用复制类,直接创建实例时传参就行 Bark.new(check_module: Bar).call # => 输出 "bar"
这种方式更符合开闭原则,扩展性更强。
内容的提问来源于stack exchange,提问作者crsde
相关产品推荐
相关产品推荐

