Ruby on Rails with Interactors

FiveStreet,我们一贯的重中之重就是要让我们的对象'Mise en place(就位)'(这个词是由Dave Bock选用的)。我们初期的成功关键就在于此。我们发现,专注于合理安排对象的位置就能够使我们在不会平添更多为弄坏东西而害怕的情况下,有更多精力来考虑添加新的特性。为达此境界,我们的策略之一就是使用interactor交互器)对象。

Interactor可以定义为你的应用的一个用例,比如,添加一条评论。在使用Interactor的地方正是对象无需互相了解就能够进行交互的地方。例如,在下面给出的例子代码中,添加一条评论还需要同一个外部对象进行交互,这个对象就是MixpanelWrapper对象。随后的代码是一个在我们的应用中对这段例子代码进行使用的、再简单不过的例子了。

添加评论交互器:

  #app/interactors/agent/add_comment.rb
  class Agent::AddComment
    attr_reader :comment
    
    def initialize(agent, comment)
      @agent = agent
      @comment = comment
    end
    
    def allowed?
      touch_log = TouchLog.find(@comment.touch_log_id)
      return false if !@comment.valid? || touch_log.agent_id != @agent.id
      return true
    end
  
    def run()
      return false if !allowed?
  
      MixpanelWrapper.track("Agent: Add Comment To Prospect", { :distinct_id => @agent.email })
  
       @comment.save
    end
  
   end

之前的代码块展示了如何创建交互器。所有的交互器都有两个 main 方法,#allowed? 何 #run。在 #allowed?方法中我们处理所有的验证。run 方法则用于运行使用及其它的代码。

评论控制器

  class Agent::CommentsController < ApplicationController
    def create
      comment = Comment.new(params[:comment])
      action = Agent::AddComment.new(current_agent, comment)
      if action.run()
        flash_success_on_redirect "Comment was added."
        redirect_to prospect_path(action.comment.touch_log)
      else
        flash_error_on_redirect "Please enter a comment."
        redirect_to prospect_path(action.comment.touch_log)
      end
    end
  end

控制器非常基础,这里的新东西是调用 Agent::AddComment.new(current_agent, comment) 而非通常的 comment = Comment.new(params[:comment]);comment.save。

在高层次上的好处是:

不利之处:

这么做会带来哪些好处:

如上所述,我们对这种做法非常满意,主要有下面几方面的原因:
  1. 首先,在某种意义上这让我想到了Rails。Interactor具有相当大的关注点分离作用,我们能够将更多精力投入添加新特性的工作中而且还不用太担心破坏已有代码。为什么能这样呢?这是因为,每个interactor都是自给自足的,它同其它的对象是完全分开的。
  2. 这些自给自足的对象使得我们可以轻松地删掉我们不再需要的代码。有时这会非常有用,比如,我们添加了一个原本我们认为很神奇的一个新特性,后来发现它并不是那么神奇。
  3. 这种方式使得我们可以更加容易的对用例进行重用。如果我想在系统中的别任何地方发布一条评论,我只需要再次调用一下这个对象。
  4. 测试比以前简单了10倍。这种方式在某些时候尤其的好,比如,在最后期限之前你的时间不够用了,没时间写出“完美的”方法了。只要有测试就ok了,以后总可以对它们进行重构。、
  5. 将来再有新人加入公司的话,他们最大的要求就是要了解,Agent::AddComment是用来做什么的?