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

.

+3


source to share


1 answer


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 .

+7


source







All Articles