2013-02-18 87 views
0

我有一个简单的类用一个简单的方法定义有一个方法重新定义另一个类的方法

class Printer 
    def print 
    p '1' 
    end 
end 

现在我介绍一个单独的脚本,通过添加一些额外的东西打印重新定义了打印方法

class Printer 

    alias :old_print :print 
    def print 
    old_print 
    p '2' 
    end 
end 

我可以通过编程来实现吗?

module Test 

    def self.redefine_print(arg) 
    # redefine Printer's print method so that it will print all of the stuff it should 
    # print, followed by the arg I specified 
    end 
end 

因此,一个样品的相互作用可能看起来像

>>>a = Printer.new 
>>>a.print 
1 
>>>Test.redefine_print("new stuff") 
>>>a.print 
1 
new stuff 
>>>Test.redefine_print("more") 
>>>a.print 
1 
new stuff 
more 

如果现有实例是由变化的影响(因为打印机的任何实例将被创建,做它的打印,然后马上布置这是确定)

+0

你有什么特别的理由要重新定义这个方法吗?为什么不在'Printer'上添加一个方法来添加更多要打印的内容? – 2013-02-18 19:51:54

+0

你*正在以编程方式进行。没有理由不能在类定义之外做同样的事情。这就是说......目的是什么?如果你正在做的是添加在页眉/页脚/等。你不需要元编程。 – 2013-02-18 20:04:22

+0

我使用的示例非常简化,纯粹是为了查看是否有可能或不可以(在另一个类中重新定义另一个方法)。我的解决方案可能会是@RenatoZannon提到的。 – MxyL 2013-02-18 22:34:44

回答

0

您可以使用define_method或模块,但它是矫枉过正(可能非常慢)。这是可能的(简单)使用类变量和类方法代替:

class Printer 
    @@tokens = [] 

    def print 
    @@tokens.each do |token| 
     p token 
    end 
    end 

    def self.add_token(token) 
    @@tokens << token 
    end 
end 

Printer.add_token("foo") 

printer = Printer.new 
printer.print 
# foo 

Printer.add_token("bar") 
printer.print 
#foo 
#bar 

要回答你的问题,虽然,它可以通过使用class_evaldefine_method重新定义其他类的方法:

class Printer 
    def print 
    p '1' 
    end 
end 

module Test 
    def self.redefine_print(arg) 
    old_print = Printer.instance_method(:print) 
    Printer.class_eval do 
     define_method(:print) do 
     old_print.bind(self).call 
     p arg 
     end 
    end 
    end 
end 

printer = Printer.new 
printer.print 
# 1 

Test.redefine_print("new stuff") 
printer.print 
# 1 
# new stuff 

Test.redefine_print("more") 
printer.print 
# 1 
# new stuff 
# more 
+0

为什么'define_method'会变慢?一旦定义了该方法,它就不会与直接在源代码中定义的方法有所不同。我同意,但你首先采取的方式更适合这种情况,但不是一般情况。 – 2013-02-18 21:38:52

+0

不完全。 'define_method'涉及一个闭包,占用内存。在该示例中,该方法的所有以前的定义都需要保持引用。此外,它使方法缓存无效。 – 2013-02-19 00:48:57

+1

我同意你在这个具体的例子。尽管如此,'define_method'在许多情况下都很棒,但必须小心使用。关于你的代码的另一个注意事项:你应该真的使用类实例变量而不是类变量,因为类变量很容易破坏封装。例如http://martinfowler.com/bliki/ClassInstanceVariable.html – 2013-02-19 01:08:47

相关问题