为什么要用scala的蛋糕模式而不是抽象的领域? [英] Why use scala's cake pattern rather than abstract fields?

查看:235
本文介绍了为什么要用scala的蛋糕模式而不是抽象的领域?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在阅读关于通过蛋糕图案。我觉得我明白了,但我一定错过了一些东西,因为我依然看不到它的意义!为什么最好通过自己的类型声明依赖关系,而不是仅仅是抽象的领域?

I have been reading about doing Dependency Injection in scala via the cake pattern. I think I understand it but I must have missed something because I still can't see the point in it! Why is it preferable to declare dependencies via self types rather than just abstract fields?

给出了编程Scala TwitterClientComponent 使用蛋糕模式声明这样的依赖关系:

Given the example in Programming Scala TwitterClientComponent declares dependencies like this using the cake pattern:

//other trait declarations elided for clarity
...

trait TwitterClientComponent {

  self: TwitterClientUIComponent with
        TwitterLocalCacheComponent with
        TwitterServiceComponent =>

  val client: TwitterClient

  class TwitterClient(val user: TwitterUserProfile) extends Tweeter {
    def tweet(msg: String) = {
      val twt = new Tweet(user, msg, new Date)
      if (service.sendTweet(twt)) {
        localCache.saveTweet(twt)
        ui.showTweet(twt)
      }
    }
  }
}

依赖关系作为抽象字段如下?

How is this better than declaring dependencies as abstract fields as below?

trait TwitterClient(val user: TwitterUserProfile) extends Tweeter {
  //abstract fields instead of cake pattern self types
  val service: TwitterService
  val localCache: TwitterLocalCache
  val ui: TwitterClientUI

  def tweet(msg: String) = {
    val twt = new Tweet(user, msg, new Date)
    if (service.sendTweet(twt)) {
      localCache.saveTweet(twt)
      ui.showTweet(twt)
    }
  }
}

时间,这是DI实际发生的时候(据我所知),我正在努力看到蛋糕的优势,特别是当你考虑额外的键盘打字你需要做的蛋糕声明(包围特征)

Looking at instantiation time, which is when DI actually happens (as I understand it), I am struggling to see the advantages of cake, especially when you consider the extra keyboard typing you need to do for the cake declarations (enclosing trait)

    //Please note, I have stripped out some implementation details from the 
    //referenced example to clarify the injection of implemented dependencies

    //Cake dependencies injected:
    trait TextClient
        extends TwitterClientComponent
        with TwitterClientUIComponent
        with TwitterLocalCacheComponent
        with TwitterServiceComponent {


      // Dependency from TwitterClientComponent:
      val client = new TwitterClient

      // Dependency from TwitterClientUIComponent:
      val ui = new TwitterClientUI

      // Dependency from TwitterLocalCacheComponent:
      val localCache = new TwitterLocalCache 

      // Dependency from TwitterServiceComponent
      val service = new TwitterService
    }

再次与抽象字段,或多或少相同!:

Now again with abstract fields, more or less the same!:

trait TextClient {
          //first of all no need to mixin the components

          // Dependency on TwitterClient:
          val client = new TwitterClient

          // Dependency on TwitterClientUI:
          val ui = new TwitterClientUI

          // Dependency on TwitterLocalCache:
          val localCache = new TwitterLocalCache 

          // Dependency on TwitterService
          val service = new TwitterService
        }

我相信我一定不会错过蛋糕的优势!但是,目前我无法以任何其他方式声明依赖关系(构造函数,抽象字段)。

I'm sure I must be missing something about cake's superiority! However, at the moment I can't see what it offers over declaring dependencies in any other way (constructor, abstract fields).

推荐答案

p>具有自我类型注释的特征比具有现场注入的老式bean更容易组合,您可能在第二个代码片段中记住。

Traits with self-type annotation is far more composable than old-fasioned beans with field injection, which you probably had in mind in your second snippet.

让我们来看看您将建立此特征:

Let's look how you will instansiate this trait:

val productionTwitter = new TwitterClientComponent with TwitterUI with FSTwitterCache with TwitterConnection

如果您需要测试此特征,您可能会写:

If you need to test this trait you probably write:

val testTwitter = new TwitterClientComponent with TwitterUI with FSTwitterCache with MockConnection

嗯,一点点干违反。让我们改进。

Hmm, a little DRY violation. Let's improve.

trait TwitterSetup extends TwitterClientComponent with TwitterUI with FSTwitterCache
val productionTwitter = new TwitterSetup with TwitterConnection
val testTwitter = new TwitterSetup with MockConnection

此外,如果您的组件中的服务之间有依赖关系(例如UI取决于TwitterService),它们将由编译器自动解决。

Furthermore if you have a dependency between services in your component (say UI depends on TwitterService) they will be resolved automatically by the compiler.

这篇关于为什么要用scala的蛋糕模式而不是抽象的领域?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆