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

时间:2018-04-12 08:16:03

标签: ruby-on-rails ruby oop factory-pattern

我有以下课程

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并且它会正常工作但我也知道有些人不赞成以这种方式初始化服务对象的想法而且有一种方法可以通过服务类中的call,send方法初始化它。

只是想知道我该怎么做?

2 个答案:

答案 0 :(得分:2)

我认为您正在寻找的是:

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作为切入点的原因是它与lambdas的多态性。也就是说,在任何可以使用lambda的地方,您都可以将其替换为Evaluate的实例,反之亦然。

答案 1 :(得分:1)

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

如果EvaluateService中的方法不需要状态,则可以使用类方法,例如:

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