使用Cake模式和Scala中的函数之间的区别 - 为什么Cake模式有用?

时间:2016-12-28 09:29:29

标签: scala design-patterns cake-pattern

我想知道在Scala中使用函数和DI模式的区别。我想出了以下理解,我想知道这种理解是否正确。

让我们设想一个依赖图。

1)如果我们使用函数作为构建块,那么图形由作为节点的函数和作为边的参数组成。

2)如果我们使用traits作为构建块(如Cake),那么图形由作为节点的特征和作为边缘的抽象成员组成。

那么Cake模式的目的是什么?为什么2优于1?这是课程粒度。通过将函数分组为特征可以简化图形1,然后我们可以使用更小,更易理解的图形-2。相关概念的分组/聚类是一种压缩形式,可以创造理解(我们需要掌握更少的东西才能获得理解)。

这是一个不同的比较(Cake与包系统之间):

Cake类似于将相关函数分组到包中,但它超出了这个范围,因为使用名称空间(包/对象)会导致依赖关系变得难以连接,Cake正在用特征和import替换包/对象自我类型注释/抽象成员。包和Cake模式之间的区别在于,依赖项的实际实现可以使用Cake进行更改,而使用包时却无法更改。

我不知道这些类比是否有意义,如果不是,请纠正我,如果是,请向我保证。我仍然试图围绕Cake模式,以及如何将它与我已经理解的概念(函数,包)联系起来。

1 个答案:

答案 0 :(得分:2)

依赖注入(DI)通常使用getter / setter(我假设你的意思是函数)和/或构造函数params来完成。 getter / setter方法可能如下所示:

trait Logger { 
  // fancy logging stuff 
}

class NeedsALogger {
  private var l: Logger = _
  def logger: Logger = l
  def logger_=(newLogger: Logger) {
    l = newLogger
  }
  // uses a Logger here
}

我真的不喜欢getter / setter方法。无法保证依赖性被注入。如果您使用某些DI框架,您可以强制注入某些内容,但是您的DI不再与您的框架无关。现在,如果使用构造函数方法,则每当我们实例化时(无论框架如何)都必须提供依赖项:

class NeedsALogger(logger: Logger) {
  // uses a Logger here
}

现在,蛋糕图案如何适应?首先,让我们将我们的例子改编为Cake Pattern:

class NeedsALogger {
  logger: Logger => 
  // Uses a Logger here
}

我们来谈谈logger: Logger =>。这是一个自我类型,它只是将Logger的成员带入范围而不必扩展LoggerNeedsALogger不是Logger,因此我们不想扩展它。但是,NeedsALogger 需要一个Logger,这就是我们使用自我类型所做的事情。我们要求在创建Logger时必须提供NeedsALogger。用法如下:

trait FooLogger extends Logger {
  // full implementation of Logger
}

trait BarLogger extends Logger {
  // full implementation of Logger
}

val a = new NeedsALogger with FooLogger
val b = new NeedsALogger with BarLogger
val c = new NeedsALogger // compile-time error! 

正如您所看到的,我们使用任何一种方法都可以完成同样的事情。对于很多DI,构造函数方法就足够了,所以你可以根据自己的偏好选择。我个人喜欢自我类型和蛋糕模式,但我看到很多人也避免使用它。

要继续阅读有关蛋糕模式的信息,请检查this。如果您想了解更多信息,这是一个很好的下一步。