Back

一种实现模式:钩子方法 (An implement pattern: hook method)

发布时间: 2012-08-24 03:27:00

我们经常会用到hook 方法(钩子方法). 例如: before, after, ...  比如rails,比如delayed_job中。   ( We have been seen this kind of code everywhere:  before, after... in rails or other libraries such as delayed_job. they are called 'hook method' )

最基本的设想是这样的 ( the simplest implementation is as below )

def run
  before
  core_method
  after
end
def core_method;  puts 'running the core method' ; end
def before;   puts 'something happens before hand' ; end
def after;  puts 'finally...' ; end

run    # =>   'something happens before hand'
       # =>   'running the core method'
       # =>   'finally...'

尽管上面的代码也工作, 但是还有更好的办法。可读性更强。比如delayed_job 中所使用的: ( Yes, the above code works, however there's a better way to improve the readability. see the implementation from delayed_job as below )

class ParanoidNewsletterJob < NewsletterJob
  def perform
    emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) }
  end
  def before(job)
    record_stat 'newsletter_job/start'
  end

我们可以看到,delayed job 源代码中,中把hook进一步写成了一个macro ( 模拟宏)   (  We could find that Delayed_job 's source code implements the hooks as a class macro ) 

      def hook(name, *args)
        if payload_object.respond_to?(name)
          method = payload_object.method(name)
          method.arity == 0 ? method.call : method.call(self, *args)
        end
      rescue DeserializationError
        # do nothing
      end

然后就可以写成更加自然/理所当然/一目了然的方式:  ( Then, the code is more straight forward...)

      
     def invoke_job
        hook :before      # instead of:  payload_object.send(:before)
        payload_object.perform
        hook :success
      rescue Exception => e
        hook :error, e
        raise e
      ensure
        hook :after
      end

怎么样? 使用了 "hook" 做为macro, 是不是一目了然,核心方法 payload_object.perform 赫然出现。hooks 把它围绕在中心。效果是不是比原来的代码要容易了不少呢?  ( see it? it's more obvious that 'before', 'success' are hooks and the 'payload_object.perform' is the core method.  ) 

Back