【问题标题】:Scala dependency injection when using case class/companion object pattern使用案例类/伴随对象模式时的 Scala 依赖注入
【发布时间】:2017-02-23 01:27:42
【问题描述】:

在迁移到 Play 2.5 时,我采用了依赖注入设计模式,包括用于 (JDBC) 数据库访问。

在课堂上,我理解这个概念:

class Users @Inject() (db: Database)

但我还没有看到关于当您需要在案例类和伴随对象模式的方法中访问数据库时如何应用此方法的讨论。一个示例基本模型是:

package models

import anorm._
import anorm.SqlParser._
import javax.inject._

import play.api.db._
import play.api.libs.functional.syntax._
import play.api.libs.json._


case class User @Inject() (db: Database) (
    id: Option[Long] = None,
    email: String
) {
    def save = {
        id.map { id => User.findById(id) } match {
            case None => create
            case _ => update
        }
    }

    def create = db.withConnection { implicit conn =>
        SQL(
            """INSERT INTO users (email) VALUES ({email})"""
        ).on(
            'email -> email
        ).executeUpdate()

        this
    }

    def update = ...
}

object User {    
    val simple = {
        get[Option[Long]]("id") ~
        get[String]("email") map {
            case id ~ email =>
                User(id, email)
        }
    }

    def findById(id: Long) = db.withConnection { implicit conn =>
        SQL("""SELECT * FROM users WHERE id = {id}""").on('id -> id).as(User.simple.singleOpt)
    }
}

这会更改案例类的签名(使其在val simple = { ... } 中无法使用),我无法弄清楚如何在伴随对象中注入/访问数据库。在对象中尝试 @Inject() var db: Database _ 会导致我想避免的 NullPointerExceptions 世界。

在依赖注入的世界中,这种常见用例的推荐设计模式是什么?

【问题讨论】:

  • case 类并不是为了封装这样的“服务”功能,DI 也不是为了与对象一起工作而设计的

标签: scala playframework dependency-injection playframework-2.5


【解决方案1】:

一种常见的模式是将数据库功能放在一个单独的类中。在您的情况下,只需将数据留给用户:

 case class User(id: Option[Long] = None, email: String)

并将数据库功能放到一个单独的类中:

class UserRepository @Inject()(db: Database) {
    def save(user: User) = { ... }
    def create() : User = { ... }
    def findById(id: Long) : Option[User] = { ... }
}

不知道您将如何在代码中使用User 对象。但是使用这种模式,您不会携带对数据库的引用,每个用户对象基本上都会将持久性实现泄漏到使用用户对象的任何地方。也许你想拥有这个,但是你在val simple = ... 中创建User 对象的方式向我表明你想要创建只包含数据的用户对象。

现在您正在传递用户对象,并且只有在需要数据库功能时才注入UserRepository

这并不能完全回答您关于将依赖项注入伴随对象的问题,但无论如何可能会有帮助。

【讨论】:

  • 谢谢!这是一个很好的模式 - 我还应该提到我正在反对“Learning Play!Framework 2”一书中的这个先前的 Play github.com/andypetrella/play2-book-chapters/blob/master/chap4/…
  • 我将继续并将其标记为已接受的答案,因为我认为这是最接近预期问题的重构。上面书中介绍的模式似乎不是最实用的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-02-03
  • 1970-01-01
  • 1970-01-01
  • 2013-06-05
  • 1970-01-01
  • 2015-08-26
  • 2015-05-10
相关资源
最近更新 更多