我已经尝试阅读各种博客文章,试图解释alias_method_chain以及使用它的原因而不使用它。特别是,我注意到了:
http://weblog.rubyonrails.org/2006/4/26/new-in-rails-module-alias_method_chain
和
http://yehudakatz.com/2009/03/06/alias_method_chain-in-models/
我仍然没有看到alias_method_chain的任何实际用途。任何人都可以解释一些事情。
1 - 它是否仍在使用?
2 - 什么时候使用alias_method_chain?为什么?
答案 0 :(得分:104)
1 - 它还在使用吗?
显然是的,alias_method_chain()
是still used in Rails(从版本3.0.0开始)。
2 - 你什么时候用? alias_method_chain和为什么?
( 注意: 以下内容主要基于Paolo Perrotta对Metaprogramming Ruby alias_method_chain()
的讨论,你应该得到的优秀书籍。)
让我们从一个基本的例子开始:
class Klass
def salute
puts "Aloha!"
end
end
Klass.new.salute # => Aloha!
现在假设我们想要使用日志记录行为来包围Klass#salute()
。我们可以做到Perrotta称之为别名的 :
class Klass
def salute_with_log
puts "Calling method..."
salute_without_log
puts "...Method called"
end
alias_method :salute_without_log, :salute
alias_method :salute, :salute_with_log
end
Klass.new.salute
# Prints the following:
# Calling method...
# Aloha!
# ...Method called
我们定义了一个名为salute_with_log()
的新方法,并将其别名为salute()
。用于调用salute()
的代码仍然有效,但它也会获得新的日志记录行为。我们还为原始salute()
定义了一个别名,因此我们仍然可以在不记录的情况下致敬:
Klass.new.salute_without_log # => Aloha!
因此,salute()
现在称为salute_without_log()
。如果我们想要记录,我们可以调用salute_with_log()
或salute()
,它们是同一方法的别名。困惑?好!
根据Perrotta的说法,这种别名在Rails中很常见:
再看一下Rails的另一个例子 以自己的方式解决问题。一些 版本之前,包含Rails代码 同一个成语的许多例子:a 围绕别名(155)用于添加 一个方法的功能,和旧的 该方法的版本已重命名为 就像是
method_without_feature()
。除了 方法名称,每次都改变了 时间,这样做的代码是 总是一样的,全都重复 这个地方。在大多数语言中,你 无法避免那种重复。 在Ruby中,你可以撒上一些 元编程魔法超过你的 模式并将其提取到自己的模式中 方法......因而诞生了alias_method_chain()
。
换句话说,您提供了原始方法foo()
和增强型方法foo_with_feature()
,最终您使用了三种方法:foo()
,foo_with_feature()
,和foo_without_feature()
。前两个包括功能,而第三个没有。 <{3}}不是为了复制这些别名,而是为你做所有的别名。
答案 1 :(得分:7)
alias_method_chain
,而使用Module#prepend
。
答案 2 :(得分:5)
我不确定它是否已经过时了Rails 3,但它仍然在之前的版本中被广泛使用。
您可以在调用方法之前(或之后)使用它来注入某些功能,而无需修改调用该方法的任何位置。见这个例子:
module SwitchableSmtp
module InstanceMethods
def deliver_with_switchable_smtp!(mail = @mail)
unless logger.nil?
logger.info "Switching SMTP server to: #{custom_smtp.inspect}"
end
ActionMailer::Base.smtp_settings = custom_smtp unless custom_smtp.nil?
deliver_without_switchable_smtp!(mail = @mail)
end
end
def self.included(receiver)
receiver.send :include, InstanceMethods
receiver.class_eval do
alias_method_chain :deliver!, :switchable_smtp
end
end
end
这是ActionMailer的一个补充,允许在每次调用deliver!
时换掉SMTP设置。通过致电alias_method_chain
,您可以定义一个方法deliver_with_switchable_smtp!
,您可以在其中执行自定义内容,并在完成后从那里调用deliver_without_switchable_smtp!
。
alias_method_chain
将旧版deliver!
别名为您的新自定义方法,因此您的应用的其余部分甚至不知道deliver!
现在也会自定义您的自定义内容。
答案 3 :(得分:3)
是否完全使用?
Seems so。这是Rails开发人员的常见做法
你何时会使用alias_method_chain?为什么?
尽管有警告,alias_method_chain仍然是向现有方法注入功能时使用的主要策略,至少在Rails 2.x中,并且后来有很多人在扩展它。 Yehuda应该从rails 3.0中删除alias_method_chain来说明他在Rails门票中的帖子和评论。它仍然被许多扩展使用,它们在执行的某些点添加自定义行为,例如记录器,错误报告器,基准测试,数据注入等。
IMO,最好的替代方案是包含一个模块,因此你可以装饰而不是委托。 (例如,按照this post中的示例4)。这样,如果您愿意,您甚至可以单独更改对象,而不会污染类的方法。这样做的缺点是方法查找链会为您注入的每个模块增加,但这就是模块的用途。
非常有趣的问题,将会关注其他人的想法。