斯卡拉蛋糕模式的重要性

时间:2015-10-12 14:28:12

标签: scala dependency-injection cake-pattern

我已经开始学习scala一段时间了,现在看着蛋糕模式。我从here

得到了例子
Runnable

对我而言,看起来有太多的样板代码来将JPA存储库注入服务。

然而,这段代码会用更少的行数

来做同样的事情
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
  }
}

实例化两种情况。

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=>
}

第二种情况使用的代码少得多,并使用DI。你能帮我理解蛋糕模式带来的额外好处吗?

3 个答案:

答案 0 :(得分:2)

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

在测试中,你可以放入模拟impls并将它们混合在一起。在生产中,你可以使用“真实”的impls并将它们混合在一起。编译器会告诉你什么时候你做错了。

(现实情况要复杂得多,因为如果混合和匹配静态对象,你可以得到空指针问题和各种非确定性。)

答案 1 :(得分:2)

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

在我看来,你的两个例子都是蛋糕模式。至少我是如何理解它的。但马丁并没有将它命名为#34;蛋糕模式"在他的书中,我将scala mosly的知识基于一本书,所以我可能会遗漏一些东西。我的理解是,蛋糕模式是结合不同特征的想法,以实现DI

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

<强>更新

找到它:http://www.artima.com/pins1ed/modular-programming-using-objects.html27.1 The problem的最后一个分段。但正如我所说,他并不是在谈论&#34; cake&#34;在这里,虽然这个想法与你给出的文章看起来相同

更新2

我刚刚重新阅读了我的回答并理解我需要改进它,因为它没有完全回答这个问题。

你应该更喜欢&#34;蛋糕模式&#34;,因为它更简单。如果你使用Spring,你必须维护配置,无论是XML还是注释,你可能对你的课程有一些要求(我还没有使用Spring,所以我不确定是否有) ,你必须携带整个春天。使用蛋糕模式,您只需编写简单的代码(您的第二个示例很简单,您应该同意)。 scala的优点在于你可以用它做很多事情,并且只使用一些框架 - 如果你将它与java进行比较,你通常会使用更多的外部库

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

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

答案 2 :(得分:1)

在第二个示例中,您只需使用JPAUserRepository的{​​{1}}实现。但是,基本上,我认为第二种方法的问题是你通过不应该公开的业务接口暴露api(当使用findAll类型的{UserRepositor时,不应该公开api Service api {1}})

确实,蛋糕模式引入的代码比使用某些IoC框架编写的代码多一些。但您也可以稍微不同的方式构建代码。例如,编写组件特征不是针对某些服务,而是针对逻辑相关的每组服务。例如,所有类型的存储库服务都可以驻留在t2中,所有类型的业务服务都可以驻留在RespositoryComponent中。为了与spring进行比较,我们的想法是组件实现特性与bean的XML decalration相同。

要在scala中使用类似DI的弹簧,我建议您查看MacWire