蛋糕模式:每个实现一个组件,还是每个特征一个组件? [英] Cake pattern: one component per implementation, or one component per trait?
问题描述
我目前正在尝试在应用程序中使用蛋糕模式.
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]
}
如果一次使用一个UserService
实现,效果很好,但是如果我同时需要两个实现,我真的不知道该怎么做.
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.
我应该创建2个不同的组件吗?每个暴露一个不同的userService值名称? (defaultUserService/alternativeUserService).对于两个实现都使用一个组件,我不知道使用名称userService
时其他组件如何知道使用哪个实现,因为我的应用程序中有2个不同的实现.
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.
顺便说一句,当组件表示对UserRepositoryComponent
的依赖关系时,虽然并非所有实现都需要它,但我发现只有一个组件对有些奇怪吗?
想象一下,我不想构建需要两个实现的完整应用程序,但是我需要进行测试以仅构建不需要UserRepositoryComponent
的AlternativeUserService,因为必须提供这种依赖关系很奇怪将不会使用.
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?
相关问题的种类: 蛋糕模式:如何获得组件提供的所有UserService类型的对象
谢谢
推荐答案
首先,您应该将UserServiceComponent
与UserService
的实现脱钩:
First things first, you should decouple the UserServiceComponent
from the implementations of UserService
:
trait UserService extends RepositoryDelegator[User] {
def getPublicProfile(id: String): Either[Error, User]
}
trait UserServiceComponent {
val userService: UserService
}
trait DefaultUserServiceComponent extends UserServiceComponent { self: UserRepositoryComponent =>
protected class DefaultUserService extends UserService {
def getPublicProfile(id: String): Either[Error, User] = userRepository.getPublicProfile(id)
}
val userService: UserService = new DefaultUserService
}
trait AlternativeUserServiceComponent extends UserServiceComponent {
protected class AlternativeUserService extends UserService {
def getPublicProfile(id: String): Either[Error, User] = call webservice here for exemple...
}
val userService: UserService = new AlternativeUserService
}
如果看起来很冗长,那就好.蛋糕图案不是特别简洁.
If that looks verbose, well it is. The cake pattern is not particularly concise.
但是请注意,即使实际上并不需要(例如仅使用AlternativeUserService
)时,它如何解决您对UserRepositoryComponent
的依赖的问题.
But notice how it solves your problem about having a dependency to UserRepositoryComponent
even when not actually required (such as when only using AlternativeUserService
).
现在,实例化应用程序时要做的就是混合DefaultUserServiceComponent
或AlternativeUserServiceComponent
.
Now, all we have to do when instantiating the application is to mix either DefaultUserServiceComponent
or AlternativeUserServiceComponent
.
如果您碰巧需要访问两个实现,则确实应该公开两个userService值名称.好吧,实际上有3个名字,例如:
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
实现的defaultUserService - alternativeUserService用于
AlternativeUserService
实现 - mainUserService用于任何
UserService
实现(应用程序在混合时间"选择哪个).
- defaultUserService for the
DefaultUserService
implementation - alternativeUserService for the
AlternativeUserService
implementation - mainUserService for any
UserService
implementation (the application chooses which one at "mix time").
例如:
trait UserService extends RepositoryDelegator[User] {
def getPublicProfile(id: String): Either[Error, User]
}
trait MainUserServiceComponent {
val mainUserService: UserService
}
trait DefaultUserServiceComponent { self: UserRepositoryComponent =>
protected class DefaultUserService extends UserService {
def getPublicProfile(id: String): Either[Error, User] = userRepository.getPublicProfile(id)
}
val defaultUserService: UserService = new DefaultUserService
}
trait AlternativeUserServiceComponent {
protected class AlternativeUserService extends UserService {
def getPublicProfile(id: String): Either[Error, User] = ??? // call webservice here for exemple...
}
val alternativeUserService: UserService = new AlternativeUserService
}
然后您可以像这样实例化您的蛋糕:
Then you can instantiate your cake like this:
object MyApp
extends MainUserServiceComponent
with DefaultUserServiceComponent
with AlternativeUserServiceComponent
with MyUserRepositoryComponent // Replace with your real UserRepositoryComponent here
{
//val userService = defaultUserService
val mainUserService = alternativeUserService
}
在上面的示例中,明确想要访问DefaultUserService
的服务会将DefaultUserServiceComponent
视为其组件的依存关系(与AlternativeUserService
和AlternativeUserServiceComponent
相同),以及仅需要 some的服务 UserService
会将MainUserServiceComponent
作为依赖项.您可以在混合时间"决定mainUserService
所指向的服务(在这里,它指向DefaultUserService
的实现.
In the above example, services that explicitly want to access the DefaultUserService
would put DefaultUserServiceComponent
as a dependecy of their component (same for AlternativeUserService
and AlternativeUserServiceComponent
), and services that just need some UserService
would instead put MainUserServiceComponent
as a dependency. You decide at "mix time" which service mainUserService
points to (here, it points to the DefaultUserService
implementation.
这篇关于蛋糕模式:每个实现一个组件,还是每个特征一个组件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!