按照正确的工厂模式从控制器调用服务方法

call service method from a controller following correct factory patterns

我有以下class

class EvaluateService
  def initialize
  end

  def get_url
  end

  def self.evaluate_service
    @instance ||= new
  end
end

class CheckController < ApplicationController
  def index
    get_url = EvaluateService.get_url
  end
end

这里的问题是我知道我可以 evaluate_service = EvaluateService.new 并使用对象 evaluate_service.get_url 并且它会正常工作,但我也知道有些人不赞成初始化服务对象的想法这种方式,而是有一种通过调用初始化它的方法,服务中的发送方法 class.

只是想知道我该怎么做?

有多种方法可以解决这个问题。

如果EvaluateService中的方法不需要状态,你可以只使用class方法,例如:

class EvaluateService
  def self.get_url
    # ...
  end
end

class CheckController < ApplicationController
  def index
    @url = EvaluateService.get_url
  end
end

在这种情况下,EvaluateService 应该是一个模块。


如果您想要一个全局 EvaluateService 实例,可以使用 Singleton:

class EvaluateService
  include Singleton

  def get_url
    # ...
  end
end

class CheckController < ApplicationController
  def index
    @url = EvaluateService.instance.get_url
  end
end

但是全局对象可能很棘手。


或者您可以在控制器中使用辅助方法来创建服务实例(根据需要)并将其记录下来:

class EvaluateService  
  def get_url
    # ...
  end
end

class CheckController < ApplicationController
  def index
    @url = evaluate_service.get_url
  end

  private

  def evaluate_service
    @evaluate_service ||= EvaluateService.new
  end
end

甚至可以将其移至您的 ApplicationController

我想你要找的是这样的:

class Evaluate
  def initialize(foo)
    @foo = foo
  end

  def self.call(foo)
    new(foo).call
  end

  def call
    url
  end

  private

  def url
    # Implement me
  end
end

现在您可以在控制器中执行此操作:

class CheckController < ApplicationController
  def index
    @url = Evaluate.call(params)
  end
end

有些人更喜欢 #call 作为入口点的原因是它与 lambda 表达式是多态的。也就是说,在任何可以使用 lambda 的地方,都可以用它代替 Evaluate 的实例,反之亦然。