蛋糕模式:每个实现一个组件,还是每个特征一个组件? [英] Cake pattern: one component per implementation, or one component per trait?

查看:75
本文介绍了蛋糕模式:每个实现一个组件,还是每个特征一个组件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在尝试在应用程序中使用蛋糕模式.

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类型的对象

谢谢

推荐答案

首先,您应该将UserServiceComponentUserService的实现脱钩:

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).

现在,实例化应用程序时要做的就是混合DefaultUserServiceComponentAlternativeUserServiceComponent.

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视为其组件的依存关系(与AlternativeUserServiceAlternativeUserServiceComponent相同),以及仅需要 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆