I'm currently working to use the cake pattern on my application.
On exemples I have found across the web the exemples are kind of basic but doesn't involve more complex needs. What I'd like to do is not so fancy: I would like to have inside a cake pattern application, 2 services of the same type, using different implementations.
trait UserServiceComponent {
self: UserRepositoryComponent =>
val userService: UserService
class DefaultUserService extends UserService {
def getPublicProfile(id: String): Either[Error, User] = userRepository.getPublicProfile(id)
}
class AlternativeUserService extends UserService {
def getPublicProfile(id: String): Either[Error, User] = call webservice here for exemple...
}
}
trait UserService extends RepositoryDelegator[User] {
def getPublicProfile(id: String): Either[Error, User]
}
It works fine if I use one implementation of the UserService
at a time, but if I need both implementations in the same time, I don't really know how to do it.
Should I create 2 distinct components? Each one exposing a different userService value name? (defaultUserService/alternativeUserService). Using one component for both implementation I don't know how other components would be able to know which implementation is used when using the name userService
since there are 2 distinct implementations in my application.
By the way, as the component expresses the dependency to the UserRepositoryComponent
, while it is not needed by all implementations, I find it a bit weird to have only one component right?
Imagine I don't want to build the full application which needs both implementations, but I need, for tests, to build only the AlternativeUserService which doesn't need the UserRepositoryComponent
, it would be weird to have to provide this dependency as it will not be used.
Can someone give me some advices so that I know what to do?
Kind of related question: Cake pattern: how to get all objects of type UserService provided by components
Thanks
First things first, you should decouple the
UserServiceComponent
from the implementations ofUserService
:If that looks verbose, well it is. The cake pattern is not particularly concise.
But notice how it solves your problem about having a dependency to
UserRepositoryComponent
even when not actually required (such as when only usingAlternativeUserService
).Now, all we have to do when instantiating the application is to mix either
DefaultUserServiceComponent
orAlternativeUserServiceComponent
.If you happen to need to access to both implementations, you should indeed expose two userService value names. Well in fact, 3 names, such as:
DefaultUserService
implementationAlternativeUserService
implementationUserService
implementation (the application chooses which one at "mix time").By example:
Then you can instantiate your cake like this:
In the above example, services that explicitly want to access the
DefaultUserService
would putDefaultUserServiceComponent
as a dependecy of their component (same forAlternativeUserService
andAlternativeUserServiceComponent
), and services that just need someUserService
would instead putMainUserServiceComponent
as a dependency. You decide at "mix time" which servicemainUserService
points to (here, it points to theDefaultUserService
implementation.