DI在Scala与蛋糕模式

时间:2014-08-14 16:32:46

标签: scala dependency-injection

article通过Scala的Cake Pattern解释依赖注入。

我对这种模式的好处的理解是,特征可以与(生产对象)和静态检查混合在一起。

在Bonér先生的例子中,他列出了这个完成的(每个例子)代码:

UserRepositoryComponent UserServiceComponent

我根据我的理解添加了评论。

trait UserRepositoryComponent {
  val userRepository: UserRepository    // stand-alone component

  class UserRepository {      
    ...                      // actual implementation here
  }
} 
trait UserServiceComponent { 
  this: UserRepositoryComponent =>      //Requires a mixed-in UserRepo*Component

  val userService: UserService  

  class UserService {
    ...                      // actual implementation here
  }
}

我的理解是Service取决于注入Repository组件。

出于生产目的,可以使用以下内容将“生产”Repository组件连接到UserServiceComponent

object ComponentRegistry extends 
  UserServiceComponent with 
  UserRepositoryComponent 
{
  val userRepository = new UserRepository
  val userService = new UserService
}

如果我们的生产代码想要使用userRepositoryuserService,通过简单import使用它们的正确方法是什么?

认为到目前为止我理解了文章的一半,但我不确定如何使用ComponentRegistry对象。

1 个答案:

答案 0 :(得分:7)

你首先进入厄运兄弟的面包店: What are some compelling use cases for dependent method types?

要回答您的问题,使用userService的正确方法是使用其他特性并将其搞砸:

trait Example { this: UserServiceComponent => 
   def getExampleUser() = userService.getUser("ExampleUser")
}

现在无论这个新特性做什么都没有直接耦合到对象ComponentRegistry之类的东西。相反,您的应用程序变为:

object Application extends 
  Example with
  UserServiceComponent with 
  UserRepositoryComponent 
{
  val userRepository = new UserRepository
  val userService = new UserService
}

无论如何,你应该跑到山上去,因为如果你真的想要用蛋糕,你应该做更像这样的事情:

trait UserRepositoryComponent {

  type UserRepository <: UserRepositoryLike

  val userRepository: UserRepository

  trait UserRepositoryLike {
    def getUserOrSomething()
  }

}

trait UserRepositoryComponentImpl extends UserRepositoryComponent {

  type UserRepository = UserRepositoryImpl
  val userRepository = new UserRepositoryImpl

  class UserRepositoryImpl extends UserRepositoryLike {
    override def getUserOrSomething() = ???
  }

}

trait UserServiceComponent {
  this: UserRepositoryComponent =>

  type UserService <: UserServiceLike
  val userService: UserService

  trait UserServiceLike {
    def getUserNameById(id: Int): String
  }

}

trait UserServiceComponentImpl extends UserServiceComponent {
  this: UserRepositoryComponent =>

  type UserService = UserServiceImpl
  val userService = new UserServiceImpl

  class UserServiceImpl extends UserServiceLike {
    override def getUserNameById(id: Int) = userRepository.getUserOrSomething
  }

}

trait Example {
  this: UserServiceComponent =>

  def getExampleUser() = userService.getUserNameById(1)

}

object Application extends
Example with
UserRepositoryComponentImpl with
UserServiceComponentImpl

现在节省一些时间,放下蛋糕模式,然后做一些simple