DI in Scala with cake drawing
This article explains the dependency on nesting through Scala Cake Pattern
.
My understanding of this advantage of templates is that traits can be mixed in (production v. Test) with static validation.
In Mr. Boehner's example, he lists this complete (for example) code:
UserRepositoryComponent and UserServiceComponent
I have added comments in my understanding.
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
}
}
I understand it Service
depends on the component insertion Repository
.
For production purposes, you can use the following to post a "production" Repository
component to UserServiceComponent
:
object ComponentRegistry extends
UserServiceComponent with
UserRepositoryComponent
{
val userRepository = new UserRepository
val userService = new UserService
}
If our production code wanted to use userRepository
or userService
, is this the correct way to use them with a simple one import
?
I think I understand half of the article up to this point, but I'm not sure how to use the object ComponentRegistry
.
source to share
You're running headlong into fate's bakery: What are some compelling use cases for dependent method types?
To answer your question, the correct way to use userService
would be to use another trait and extract it:
trait Example { this: UserServiceComponent =>
def getExampleUser() = userService.getUser("ExampleUser")
}
Now, whatever this new trait does is not directly related to something like an object ComponentRegistry
. Instead, your application will become:
object Application extends
Example with
UserServiceComponent with
UserRepositoryComponent
{
val userRepository = new UserRepository
val userService = new UserService
}
Either way, you have to run for the hills, because if you really want to use the cake, you have to do more:
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
Now save some time, drop the cake template and make something simple .
source to share