Why everyone is using this form of definition:
trait UserServiceComponent {
def userService: UserService
trait UserService {
def findAll: List[User]
def save(user: User)
}
}
Instead of that:
trait UserService {
def findAll: List[User]
def save(user: User)
}
trait UserServiceComponent {
def userService: UserService
}
Second approach seems more universal because UserService trait is not bound to specific component instance.
Anything I'm missing?
Edit: By "more universal" I mean that you can do something like this (mix two cakes with different impl. into one):
object Program extends App with UserServiceComponent with ProductServiceComponent {
object Cake1 extends UserServiceComponentImpl with DatabaseComponent1Impl {
}
object Cake2 extends ProductServiceComponentImpl with DatabaseComponent2Impl {
}
def userService = Cake1.userService
def productService = Cake2.productService
}
// def
trait DatabaseComponent{
}
trait UserService {
}
trait UserServiceComponent {
def userService: UserService
}
trait ProductService {
}
trait ProductServiceComponent {
def productService: ProductService
}
// impl
trait DatabaseComponent1Impl extends DatabaseComponent {
}
trait DatabaseComponent2Impl extends DatabaseComponent {
}
trait UserServiceComponentImpl extends UserServiceComponent {
self:DatabaseComponent =>
def userService = new UserService {}
}
trait ProductServiceComponentImpl extends ProductServiceComponent {
self:DatabaseComponent =>
def productService = new ProductService {}
}
If you define UserService as nested trait then you'll get an exception: type mismatch; found: Program.Cake1.UserService, required: Program.UserService
In your second construction, the population of the global namespace is doubled for no good reason. With the classic Cake construction a component is self-contained and it injects exactly one name into the global namespace.
In either event, the characteristic of the component (here trait UserService
) is equally available whether structured as classic Cake or your alternative. That is, your alternative is by no means "more universal."
Randall Schulz' answer is absolutely correct. I'd only add that sometimes the second form (with top-level UserService
) is inevitable. For example, when you have to pass components from "outer" cake to "inner" cake:
trait ExampleComponent {
def example: Example
}
trait Example {
def doSomething()
}
trait DefaultExampleComponent {
override val example = new Example {
// ...
}
}
trait SomeOtherComponent { self: ExampleComponent =>
object InnerCake extends ExampleComponent {
override def example = self.example
}
}
object TopLevelCake extends DefaultExampleComponent with SomeOtherComponent
If Example
was an inner trait of ExampleComponent
, then assignment
override def example = self.example
wouldn't be possible, because self.example
has type SomeOtherComponent.this.type#Example
but InnerCake.example
should be of type this.type#Example
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.