如果您仍然必须传递参数,那么依赖注入有什么意义呢?

What's the point of dependency injection if you still have to pass in an argument?

我在理解依赖注入的基本概念时遇到了一些困难。 (我正在使用带有 play-slick 模块的 Play 2.5)假设我有一个 class Users 需要数据库连接。

package models

@Singleton
class Users @Inject() (dbConfigProvider: DatabaseConfigProvider) {

  private val db = dbConfigProvider.get[JdbcProfile].db

  private val users = TableQuery[UserTable]

  private val setupAction = DBIO.seq(users.schema.create)

  private val setupFuture: Future[Unit] = db.run(setupAction)

  def getAll(): Future[Seq[User]] = setupFuture.flatMap(_ =>
    db.run(users.result)
  )

  // More methods like the previous
}

当我有一个视图需要访问这些方法时,我希望依赖注入系统为我填充 dbConfigProvider 依赖,就像这样。

package views

class UserSearch {

  def index(implicit ec: ExecutionContext): Future[String] = Future(
    (new Users).getAll().map(seq => seq.map(user => user.name).mkString(" "))
  )

}

然而,这给了我一个编译错误,我被迫使 dbConfigProvider 成为我的视图的依赖项并显式传递它。在这种情况下,我最终从调用视图的控制器中获得 dbConfigProvider

package views

class UserSearch @Inject (dbConfigProvider: DatabaseConfigProvider) {

  def index(implicit ec: ExecutionContext): Future[String] = Future(
    (new Users(dbConfigProvider)).getAll().map(seq =>
      seq.map(user => user.name).mkString(" "))
  )

}

我假设我误解了依赖注入的工作原理。

所以我的问题如下:

  1. 那么在我的模型中使用 @Inject() 关键字有什么意义 Users

  2. 我的设计模式有缺陷吗?我希望 UsersUserSearch 成为对象,但是我不能对它们使用依赖注入。

  3. 万一有人熟悉 Slick,我的 getAll() 方法是否适合使用 slick?这甚至是编写异步代码的正确方法吗?

DI 的优点之一是易于使用其他实现,这在测试中特别有用,您可以在其中传递对参数的模拟。

例如,如果您收到一个将调用外部 API 的 class (MyExternalClass) 实例,您可以改为发送一个子 class ( MyExternalSubClass extends MyExternalClass) 将覆盖调用 API 的方法,并且只是 return 预配置的 json

这里还列出了几个优点(和缺点)(网络上还有许多其他有趣的文章):

感谢@MichaelZajac 的评论,我将 UserSearch 更改为这样声明:

class UserSearch @Inject (users: Users)

现在我的控制器设置如下:

class UsersController @Inject()(userSearch: UserSearch) extends Controller {

  def index = Action.async {
    implicit request => userSearch.index().map(Ok(_))
  }

}

这直接回答了我的第一个问题,看到它的实际效果也回答了我的第二个问题。我现在收到 SQL 错误,但至少我的项目可以编译。后来我想出了我的第三个问题——原来没有理由创建 table 方案,因为在我的情况下它是由播放进化文件完成的,因此我删除了 setupFuture.flatMap 部分,即使它可以很好地工作,并且不会做任何愚蠢的事情,比如创建 table 两次,或者你可能需要在 table creation/start-up.

上做任何其他事情