蛋糕模式在scala中的重要性
importance of cake pattern in scala
我已经开始学习 scala 一段时间了,现在正在研究蛋糕模式。我从 here
得到了例子
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。你能帮我了解蛋糕模式带来的额外优势吗?
与 IoC 类型的代码注入系统相比,蛋糕模式为您提供的是,在编译时,您对将要使用的实现具有明确的依赖性,而不是涉及针对运行时检查的设置一堆 XML 文件或注释。也就是说,区别是编译时 vs 运行时。
在测试中,您可以放入模拟 impl 并将它们混入。在生产中,您可以使用 "real" impl 并将它们混入。当您做错了什么时,编译器会告诉您。
(实际情况要复杂得多,因为如果混合和匹配静态对象,您可能会遇到空指针问题和各种不确定性。)
据我了解,没有太大区别。其实蛋糕图案是IoC
。这只是实现 IoC
和 DI
的想法,没有单独的 DI
框架,而只是使用 scala 代码。除非您需要更多功能,否则您可能更喜欢它而不是单独的 DI
容器。
而且在我看来你的两个例子都是蛋糕图案。至少我是这么理解的。但是 Martin 没有在他的书中将其命名为 "cake pattern",而且我对 scala mos 的了解主要基于一本书,所以我可能会遗漏一些东西。我的理解是,蛋糕模式是结合不同特征的想法,以实现 DI
我记得Martin在他的书中特别提到,在scala中使用DI
-container如Spring是可以的,可惜我找不到这个地方
更新
找到它:http://www.artima.com/pins1ed/modular-programming-using-objects.html 请参阅 27.1 The problem
的最后一段。但正如我所说,他在这里不是在谈论 "cakes",尽管这个想法从你给的文章中看起来是一样的
更新 2
我刚刚重读了我的回答,我明白我需要改进它,因为它没有完全回答问题。
你应该更喜欢"cake pattern",因为它更简单。如果你用了Spring,你要维护配置,不管是XML还是注解,你可能对你的类也有一些要求(我没用过Spring ,所以我不确定是否有),而且你必须随身携带整个Spring。使用蛋糕模式,您只需编写尽可能简单的代码(您的第二个示例很简单,您应该同意)。 scala 的好处在于你可以用它做很多事情,并且只使用几个框架 - 如果你将它与 java 进行比较 - 你通常会使用更多的外部库
如果您需要更高级的功能,例如代理 - 您可以切换到 Spring,或者继续使用 Scala 并使用语言本身解决您的问题,希望 Scala 非常强大并且应该涵盖更复杂的情况.
您提供的两个代码片段之间的区别只是抽象:第一个代码片段对存储库和服务中定义的操作有更多的抽象,这些不是模式的一部分。我觉得这不是必需的,但作者决定这样展示。
在第二个示例中,您只需使用 JPAUserRepository
的 findAll
实现。但是,基本上,我认为第二种方法的问题是你通过不应该公开的业务接口公开 api(又名 UserRepositor
api 在使用对象时不应该公开Service
类型 t2
)
的确,蛋糕模式引入的代码比您使用某些 IoC 框架编写的代码要多一些。但是你也可以用稍微不同的方式来构造你的代码。例如,编写组件特征不是针对某个服务,而是针对逻辑上相关的一组服务。例如,所有类型的存储库服务可能驻留在 RespositoryComponent
中,而所有类型的业务服务可能驻留在 BusinessLogicComponent
中)。与 spring 进行比较,其思想在于组件实现特性与 bean 的 XML decalration 相同。
要在 Scala 中像 DI 一样使用 spring 我建议你看看 MacWire
我已经开始学习 scala 一段时间了,现在正在研究蛋糕模式。我从 here
得到了例子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。你能帮我了解蛋糕模式带来的额外优势吗?
与 IoC 类型的代码注入系统相比,蛋糕模式为您提供的是,在编译时,您对将要使用的实现具有明确的依赖性,而不是涉及针对运行时检查的设置一堆 XML 文件或注释。也就是说,区别是编译时 vs 运行时。
在测试中,您可以放入模拟 impl 并将它们混入。在生产中,您可以使用 "real" impl 并将它们混入。当您做错了什么时,编译器会告诉您。
(实际情况要复杂得多,因为如果混合和匹配静态对象,您可能会遇到空指针问题和各种不确定性。)
据我了解,没有太大区别。其实蛋糕图案是IoC
。这只是实现 IoC
和 DI
的想法,没有单独的 DI
框架,而只是使用 scala 代码。除非您需要更多功能,否则您可能更喜欢它而不是单独的 DI
容器。
而且在我看来你的两个例子都是蛋糕图案。至少我是这么理解的。但是 Martin 没有在他的书中将其命名为 "cake pattern",而且我对 scala mos 的了解主要基于一本书,所以我可能会遗漏一些东西。我的理解是,蛋糕模式是结合不同特征的想法,以实现 DI
我记得Martin在他的书中特别提到,在scala中使用DI
-container如Spring是可以的,可惜我找不到这个地方
更新
找到它:http://www.artima.com/pins1ed/modular-programming-using-objects.html 请参阅 27.1 The problem
的最后一段。但正如我所说,他在这里不是在谈论 "cakes",尽管这个想法从你给的文章中看起来是一样的
更新 2
我刚刚重读了我的回答,我明白我需要改进它,因为它没有完全回答问题。
你应该更喜欢"cake pattern",因为它更简单。如果你用了Spring,你要维护配置,不管是XML还是注解,你可能对你的类也有一些要求(我没用过Spring ,所以我不确定是否有),而且你必须随身携带整个Spring。使用蛋糕模式,您只需编写尽可能简单的代码(您的第二个示例很简单,您应该同意)。 scala 的好处在于你可以用它做很多事情,并且只使用几个框架 - 如果你将它与 java 进行比较 - 你通常会使用更多的外部库
如果您需要更高级的功能,例如代理 - 您可以切换到 Spring,或者继续使用 Scala 并使用语言本身解决您的问题,希望 Scala 非常强大并且应该涵盖更复杂的情况.
您提供的两个代码片段之间的区别只是抽象:第一个代码片段对存储库和服务中定义的操作有更多的抽象,这些不是模式的一部分。我觉得这不是必需的,但作者决定这样展示。
在第二个示例中,您只需使用 JPAUserRepository
的 findAll
实现。但是,基本上,我认为第二种方法的问题是你通过不应该公开的业务接口公开 api(又名 UserRepositor
api 在使用对象时不应该公开Service
类型 t2
)
的确,蛋糕模式引入的代码比您使用某些 IoC 框架编写的代码要多一些。但是你也可以用稍微不同的方式来构造你的代码。例如,编写组件特征不是针对某个服务,而是针对逻辑上相关的一组服务。例如,所有类型的存储库服务可能驻留在 RespositoryComponent
中,而所有类型的业务服务可能驻留在 BusinessLogicComponent
中)。与 spring 进行比较,其思想在于组件实现特性与 bean 的 XML decalration 相同。
要在 Scala 中像 DI 一样使用 spring 我建议你看看 MacWire