6

我已经开始学习 scala 一段时间了,现在正在研究蛋糕图案。我从这里得到了例子

trait UserRepositoryComponent {
  def userLocator: UserLocator

  trait UserLocator {
    def findAll: List[User]
  }
}

trait UserRepositoryJPAComponent extends UserRepositoryComponent {
  val em: EntityManager

  def userLocator = new UserLocatorJPA(em)

  class UserLocatorJPA(val em: EntityManager) extends UserLocator {
    def findAll = {
      println("Executing a JPA query")
      List(new User, new User)
    }
  }
}

trait UserServiceComponent {
  def userService: UserService

  trait UserService {
    def findAll: List[User]
  }
}

trait DefaultUserServiceComponent extends UserServiceComponent {
  this: UserRepositoryComponent =>

  def userService = new DefaultUserService

  class DefaultUserService extends UserService {
    def findAll = userLocator.findAll
  }
}

对我来说,将 JPA 存储库注入服务似乎有太多样板代码。

然而,这段代码可以用更少的行数做同样的事情

trait UserRepository {
  def findAll
}

trait JPAUserRepository extends UserRepository {
  val em: EntityManager
  def findAll = {
    em.createQuery
    println("find using JPA")
  }
}

trait MyService {
  def findAll
}

trait MyDefaultService extends MyService {
  this: UserRepository=>
}

实例化这两种情况。

val t1 = new DefaultUserServiceComponent with UserRepositoryJPAComponent {
  val em = new EntityManager()
}
t1.userService.findAll


val t2 = new MyDefaultService with JPAUserRepository {
  val em = new EntityManager
}

t2.findAll

第二种情况使用更少的代码,并使用 DI。你能帮我了解蛋糕图案带来的额外优势吗?

4

3 回答 3

2

与 IoC 类型的代码注入系统相比,蛋糕模式为您提供的是,在编译时,您对要使用的实现有明确的依赖关系,而不是涉及针对一堆 XML 文件或运行时检查的设置。注释。也就是说,区别在于编译时间与运行时间。

在测试中,您可以放入模拟 impl,然后将它们混合。在生产中,您可以使用“真实”的 impl,然后将它们混合。编译器会在您做错时告诉您。

(实际情况要复杂得多,因为如果混合和匹配静态对象,您可能会遇到空指针问题和各种不确定性。)

于 2015-10-12T15:32:12.133 回答
2

据我了解,没有太大区别。其实蛋糕图案是IoC。这只是实现IoCand的想法DI,没有单独的DI框架,而只是使用 scala 代码。DI除非您需要更多功能,否则您可能应该更喜欢它而不是单独的容器。

在我看来,你的两个例子都是蛋糕图案。至少我是这么理解的。但是 Martin 在他的书中没有将其命名为“蛋糕模式”,而我对 scala mosly 的了解基于一本书,所以我可能会遗漏一些东西。我的理解是蛋糕模式是结合不同特征来实现的想法DI

我认为 Martin 在他的书中特别提到,DI在 scala 中使用 Spring 等容器是可以的,但不幸的是我找不到这个地方

更新

找到它:http ://www.artima.com/pins1ed/modular-programming-using-objects.html请参阅27.1 The problem. 但是正如我所说,他在这里不是在谈论“蛋糕”,尽管从您给出的文章中看这个想法是一样的

更新 2

我刚刚重读了我的答案并明白我需要改进它,因为它并没有完全回答这个问题。

您应该更喜欢“蛋糕图案”,因为它更简单。如果你使用Spring,你必须维护配置,无论是XML还是注解,你可能对你的类也有一些要求(我没有使用过Spring,所以我不确定有没有),你有带上整个春天。使用蛋糕模式,您只需编写尽可能简单的代码(您的第二个示例很简单,您应该同意)。scala 的好处是你可以用它做很多事情,并且只使用几个框架——如果你将它与 java 进行比较——你通常会使用更多的外部库

如果你需要更高级的功能,比如代理——你可以切换到 Spring,或者继续使用 Scala 并用语言本身解决你的问题,希望 scala 非常强大,甚至可以涵盖复杂的情况。

您提供的两个代码片段之间的区别只是抽象:第一个对存储库和服务中定义的操作有一个抽象,这些不是模式的一部分。我觉得这不是必需的,但作者决定这样展示它。

于 2015-10-12T16:25:42.063 回答
1

在第二个示例中,您只需使用JPAUserRepository'findAll实现。但是,基本上,在我看来,第二种方法的问题是您通过不应该公开的业务接口公开 api(也就是在使用typeUserRepositor的对象时不应该公开 api )Servicet2

事实上,蛋糕模式引入的代码比使用某些 IoC 框架编写的代码要多。但是你也可以用稍微不同的方式来构建你的代码。例如,不是针对某些服务编写组件特征,而是针对逻辑相关的服务组编写组件特征。例如,所有类型的存储库服务都可以驻留在) 中RespositoryComponent,所有类型的业务服务都可以驻留在BusinessLogicComponent) 中。与 spring 相比,其思想在于组件实现 trait 与 bean 的 XML 声明相同。

要在scala中使用像DI这样的弹簧,我建议你看看MacWire

于 2015-10-13T14:30:05.783 回答