两步施工。有用还是只是代码味道?

时间:2015-02-02 10:51:07

标签: ruby context-injection

通常我希望一旦构造了一个对象,它就应该可以使用了。没有两步建设。如果你需要调用两个构造函数来使用一个对象,那么是非常错误的......对吗?

class Contact
  attr_accessor :auth_token

  def initialize(contact_hash)
     ...
  end

  def edit(...)
     auth_token.can! :read, self
  end
end

token = AuthorizationToken.new(session)
contact = SomeService.get_contact(...)

contact.edit(...)
# raise error because auth_token is not set

contact.auth_token = token

contact.edit(...)

上面的代码代表了我当前的困境:我希望 SomeService 给我联系对象,但我不希望该服务关注现有会话,或者授权。

我目前的做法是增加这个额外的课程:

class QueryService
  def initialize(session)
    token = AuthorizationToken(session)
  end

  def get_contact
    contact = SomeService.get_contact(...)
    contact.token = token
  end
end

contact = QueryService.new(session).get_contact(...)
contact.edit(...)

此解决方案让我可以最自由地在核心域对象联系人中使用授权问题,在外部类 AuthorizationToken 中实现它们,并实现不关心的服务当前用户会话 SomeService

然而,这两步建设正在扼杀我。感觉很奇怪:某个操作没有完全初始化的对象???

这不是依赖注入的简单情况,更确切地说是上下文注入。所以关于在Ruby中避免DI的大部分文章并没有真正解决我的问题。我想知道是否有一个更多的Ruby方式来解决这个问题,或者这个问题就像它可以得到的一样干净。

1 个答案:

答案 0 :(得分:0)

看起来您的Contact类有两个目的 - 存储联系人数据并执行一些授权请求 - 所以是的,它确实违反了Single Responsibility Principle

这可以通过将Contact类拆分为两个来修复 - 一个可能是Struct,甚至是一个普通的哈希来存储数据,第二个用于处理请求。

我认为最常用的 Ruby 方法是从SomeService返回哈希值,稍后用Contact.new(data, auth_token)实例化。