蛋糕模式:每个实现一个组件,还是每个特征一个组件?

2023-11-29

我目前正在努力在我的应用程序中使用蛋糕图案。

在我在网上找到的示例中,这些示例是基本的,但不涉及更复杂的需求。我想做的事情并不是那么奇特:我想在蛋糕模式应用程序中拥有两个相同类型的服务,使用不同的实现。

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一次,但如果我同时需要两种实现,我真的不知道该怎么做。

我应该创建 2 个不同的组件吗?每个都暴露不同的 userService 值名称? (默认用户服务/替代用户服务)。使用一个组件来实现两种实现我不知道其他组件如何能够知道使用名称时使用的是哪种实现userService因为我的应用程序中有两个不同的实现。

顺便说一句,由于组件表达了对UserRepositoryComponent,虽然并非所有实现都需要它,但我觉得只有一个组件有点奇怪,对吗? 想象一下,我不想构建需要两种实现的完整应用程序,但为了测试,我需要仅构建不需要的 AlternativeUserServiceUserRepositoryComponent,必须提供此依赖项会很奇怪,因为它不会被使用。

有人可以给我一些建议,以便我知道该怎么做吗?

相关问题类型:Cake模式:如何获取组件提供的所有UserService类型的对象

Thanks


首先,你应该解耦UserServiceComponent从实施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
}

如果这看起来很冗长,那么确实如此。蛋糕的图案不是特别简洁。

但请注意它如何解决您的依赖问题UserRepositoryComponent即使实际上并不需要(例如仅使用AlternativeUserService).

现在,在实例化应用程序时我们所要做的就是混合DefaultUserServiceComponent or AlternativeUserServiceComponent.

如果您碰巧需要访问这两个实现,则确实应该公开两个 userService 值名称。其实有3个名字,比如:

  • 默认用户服务DefaultUserService执行
  • 替代用户服务AlternativeUserService执行
  • mainUserService 适用于任何UserService实现(应用程序在“混合时间”选择哪一个)。

举例来说:

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
}

然后你可以像这样实例化你的蛋糕:

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 and AlternativeUserServiceComponent),以及刚需要的服务some UserService而是会放MainUserServiceComponent作为依赖。您在“混合时间”决定哪种服务mainUserService指向(这里,它指向DefaultUserService执行。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

蛋糕模式:每个实现一个组件,还是每个特征一个组件? 的相关文章

随机推荐