【问题标题】:Binding/Injecting a Scala function (not whole class) using Guice?使用 Guice 绑定/注入 Scala 函数(不是整个类)?
【发布时间】:2016-07-26 19:41:36
【问题描述】:

我想将我的UserDao 对象的byId 方法注入我的Authentication 对象的构造函数中。我想避免注入整个班级。

// Has def byId(id: UserId): Option[User]
bind(classOf[UserDao]).asEagerSingleton()

// Something like this
bindMethod(classOf[UserDao], _.byId)

// Constructor takes a (UserId) => Option[User] function
bind(classOf[Authentication]).asEagerSingleton()

我正在使用带有 Play 框架的 Guice。任何建议表示赞赏

【问题讨论】:

    标签: scala playframework playframework-2.0 guice


    【解决方案1】:

    其实你要的是封装?

    如果是这样,我建议使用这样的代码:

    // User model
    case class User(id: UUID, name: String)
    
    trait AuthenticationUserDao{
      def findById: Option[User]
    }
    
    class UserDao extends AuthenticationUserDao {
      override def findById: Option[User] = ???
      def add(user: User): Boolean = ???
      def delete(userId: UUID): Boolean = ???
    }
    
    // ...
    
    class Authentication @Inject() (
                                     authenticationUserDao: AuthenticationUserDao
                                   ) extends Controller {
    
      // Here only the method findById is available (not tested, but i guest it's the case here)
    
      def findUser(userId: UUID) = Action {
        authenticationUserDao.findById(userId)
      }
    
    }
    
    // ...
    
    bind(classOf[UserDao]).to(classOf[AuthenticationUserDao])
    

    希望我已经很好理解了。

    【讨论】:

    • 感谢您的回答,但我只想将一个函数传递给我的身份验证类。不是整个班级或特质。 Scala 和 Java 8 的好处是能够将简单的 lambdas 作为类之间的依赖关系传递,这比传递整个类或特征要干净得多,也更可测试。
    • 我不知道。谢谢你的解释。
    【解决方案2】:

    你问这个是对的,因为它可以大大简化测试。诀窍是使用@Provides 注解:

    TL;DR

    class MyController @Inject() (byId: (UserId) => Option[User]) extends Controller { ... }
    
    @Provides
    def userDao(aDependency: Any): UserDao = // return UserDao, note aDependency will be injected
    
    @Provides
    def byId: (UserId) => Option[User] = userDao.byId // note: this method will call the other @Provides method 'userDao'
    

    说明

    最终byId: (UserId) => Option[User] 转换为scala.Function1[UserId, Option[User]] 但是您可以使用语法糖声明函数依赖关系:

    class MyController @Inject() (_addTwo: (Int, Int) => Int) extends Controller {
    
      def addTwo(a: Int, b: Int) = Action {
        Ok(_addTwo(a, b).toString) // call the injected function 
      }
    
    }
    

    然后在你的 Module.scala 中创建一个返回函数的方法:

    @Provides
    def addTwo: (Int, Int) => Int = (a, b) => a + b
    

    您可以在 @Provides 方法中执行所有常见的 Scala 操作,例如返回一个部分应用的函数:

    @Provides
    def addTwo: (Int, Int) => Int = addThree(0, _:Int, _:Int)
    
    def addThree(a: Int, b: Int, c: Int): Int = a + b + c
    

    为避免冲突,您还可以使用@Named 注解:

    class MyController @Inject() (@Named("addTwo") _addTwo: (Int, Int) => Int, 
                                  @Named("subtractTwo") _subTwo: (Int, Int) => Int) 
                                  extends Controller { ... }
    
    @Provides
    @Named("addTwo")
    def addTwo: (Int, Int) => Int = (a, b) => a + b
    
    @Provides
    @Named("subtractTwo")
    def subTwo: (Int, Int) => Int = (a, b) => a - b
    

    【讨论】:

    • def byId: (User) => Option[User] 是如何编译的?当我调用userDao 时,我的代码要求我提供参数aDependency。没有这个论点,我不能使用byId。有没有一种方法可以自动从 Guice 捕获所有依赖项,而无需为所有依赖项编写 @Provides?
    猜你喜欢
    • 2019-06-06
    • 1970-01-01
    • 2016-09-04
    • 1970-01-01
    • 2017-01-18
    • 2012-10-16
    • 1970-01-01
    • 2018-04-25
    • 1970-01-01
    相关资源
    最近更新 更多