简体   繁体   English

斯卡拉蛋糕模式的重要性

[英]importance of cake pattern in scala

I have started learning scala for a while now and now looking at cake pattern. 我已经开始学习scala一段时间了,现在看着蛋糕模式。 I got the example from 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
  }
}

To me it looks like too many boilerplate code to get the JPA repository injected to service. 对我而言,看起来有太多的样板代码来将JPA存储库注入服务。

However this code would do the same with much lesser number of lines 但是,此代码将使用更少数量的行来执行相同操作

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

Instantiating both scenarios. 实例化两种方案。

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

Second scenario uses much less code, and uses DI. 第二种情况使用更少的代码,并使用DI。 Can you help me understand what extra advantages cake pattern brings. 你能帮我理解蛋糕模式带来的额外好处吗?

What the cake pattern gives you compared to an IoC type of code injection system is that at compile time you have an explicit dependency on the implementation you are going to use as opposed to a set up which involves runtime checks against a bunch of XML files or annotations. 与IoC类型的代码注入系统相比,蛋糕模式提供的是,在编译时,您将明确依赖于将要使用的实现,而不是涉及对一堆XML文件进行运行时检查的设置或注释。 That is to say, the distinction is compile time vs runtime. 也就是说,区别在于编译时与运行时。

In testing, you can put in mock impls and just mix them in. In production, you can use the "real" impls and just mix those in. The compiler will tell you when you did something wrong. 在测试中,你可以放入模拟impls并将它们混合在一起。在生产中,你可以使用“真实”的impls并将它们混合在一起。编译器会告诉你什么时候你做错了。

(The reality is much more complex as you can get null pointer issues and various sorts of non-determinism if mixing and matching static objects.) (现实情况要复杂得多,因为如果混合和匹配静态对象,你可以得到空指针问题和各种非确定性。)

As I understand it, there is no much difference. 据我了解,没有太大区别。 Actually cake pattern is IoC . 实际上蛋糕模式是IoC It's just the idea of implementing IoC and DI , without separate DI framework, but just with scala code. 这只是实现IoCDI的想法,没有单独的DI框架,只是使用scala代码。 You probably should prefer it over separate DI container unless you need more functionality. 除非您需要更多功能,否则您可能更喜欢它而不是单独的DI容器。

Also it looks to me like both of your examples are cake patterns. 在我看来,你的两个例子都是蛋糕模式。 At least that's how I understand it. 至少这是我理解它的方式。 But Martin didn't name it "cake pattern" in his book, and I base my knowledge of scala mosly on a single book, so I might be missing something. 但马丁并没有在他的书中将其命名为“蛋糕模式”,而且我将scala mosly的知识基于一本书,所以我可能会遗漏一些东西。 My understanding is that cake pattern is idea combining different traits to achieve DI 我的理解是,蛋糕模式是结合不同特征以实现DI想法

I think Martin specifically mentioned in his book, that it is alright to use DI -containers such as Spring in scala, but I unfortunately cannot find this place 我认为Martin在他的书中特别提到,在scala中使用像Eclipse这样的DI容器是可以的,但遗憾的是我找不到这个地方

Update 更新

Found it: http://www.artima.com/pins1ed/modular-programming-using-objects.html See last subparagraph of 27.1 The problem . 找到它: http//www.artima.com/pins1ed/modular-programming-using-objects.html27.1 The problem最后一个27.1 The problem But as I said, he is not talking about "cakes" here, though the idea looks the same from the article you gave 但正如我所说,他并不是在谈论“蛋糕”,尽管这个想法与你给出的文章看起来是一样的

Update 2 更新2

I've just reread my answer and understood that I need to improve it, as it does not fully answers the question. 我刚刚重读了我的答案并理解我需要改进它,因为它没有完全回答这个问题。

You should prefer "cake pattern", because it is simpler. 你应该更喜欢“蛋糕模式”,因为它更简单。 If you use Spring, you have to maintain configuration, whether it is XML or annotations, you may also have some requirements over your classes (I haven't used Spring, so I'm not sure whether there are any), and you have to bring whole Spring with you. 如果你使用Spring,你必须维护配置,无论是XML还是注释,你可能对你的类有一些要求(我没有使用Spring,所以我不确定是否有),你有随身携带整个春天。 With cake pattern you just write code as simple as it is (your second example is simple, you should agree). 使用蛋糕模式,您只需编写简单的代码(您的第二个示例很简单,您应该同意)。 What's nice about scala is that you can do a lot of stuff with it, and use only a few frameworks - if you compare it to java, - you usually use many more external libraries scala有什么好处,你可以用它做很多东西,只使用几个框架 - 如果你把它与java比较, - 你通常会使用更多的外部库

If you ever need more advanced functionality, like proxies - you may switch to Spring, or continue use Scala and solve your problems with the language itself, hopefully scala is extremely powerful and should cover even complicated cases. 如果你需要更高级的功能,比如代理 - 你可以切换到Spring,或继续使用Scala并用语言本身解决你的问题,希望scala非常强大,甚至应该涵盖复杂的情况。

The difference between two code pieces you provided is just abstraction: the first one has one more abstraction over operations defined in repository and service, and these are not part of the pattern. 您提供的两个代码段之间的区别只是抽象:第一个对存储库和服务中定义的操作有一个抽象,而这些不是模式的一部分。 I do not feel like this is required, but author decided to show it like this. 我觉得这不是必需的,但作者决定这样展示。

In the second example you just use JPAUserRepository 's findAll implementation. 在第二个示例中,您只需使用JPAUserRepositoryfindAll实现。 But, basically, the problem of second approach in my opinion is that you expose api via business interface that shouldn't be exposed(aka UserRepositor api should't be exposed when using object of Service type t2 ) 但是,基本上,我认为第二种方法的问题是你通过不应该暴露的业务接口公开api(当使用Service类型t2对象时,不应该暴露UserRepositor api)

Indeed cake pattern introduces a bit more code than you can write using some IoC framework. 确实,蛋糕模式引入的代码比使用某些IoC框架编写的代码多一些。 But you can also structure your code in slightly different way. 但您也可以稍微不同的方式构建代码。 For example, writing component trait not per some service, but per group of services that are logically related. 例如,编写组件特征不是针对某些服务,而是针对逻辑相关的每组服务。 As an example, all kind of Repository services may reside in RespositoryComponent and all kind of business services may reside in BusinessLogicComponent ). 例如,所有类型的存储库服务都可以驻留在RespositoryComponent并且所有类型的业务服务都可以驻留在BusinessLogicComponent To compare with spring, the idea is in that component implementaion trait is just the same XML decalration of beans. 为了与spring进行比较,我们的想法是组件实现特性与bean的XML decalration相同。

To use spring like DI in scala I suggest you to look at MacWire 要在scala中使用像DI这样的弹簧,我建议你看一下MacWire

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM