使用Scala进行依赖注入

时间:2014-02-23 14:04:28

标签: scala dependency-injection

我正在寻找一种在Scala中进行依赖注入的方式,如Spring中的Spring或Unity,我发现没有什么真正有趣的。

  • MacWire:我不明白这个好处,因为我们必须给线上课[CASS]。那么,如果在调用wire时给出实现,那又有什么意义呢?我可以做新的CASS,它会是一样的。
  • 自我类型的蛋糕模式:似乎没有回答我正在搜索的内容。

所以我决定让我的实施并问你的想法是什么,因为令我惊讶的是,之前没有做过这样的事情。也许我的实现在现实生活中也有很多问题。

所以这是一个例子:

trait Messenger {
  def send
}

class SkypeMessenger extends Messenger {
  def send = println("Skype")
}

class ViberMessenger extends Messenger {
  def send = println("Viber")
}

我希望在我的应用程序中随处注入仅在一个地方配置的实现:

object App {
  val messenger = Inject[Messenger]

  def main(args: Array[String]) {
    messenger.send
  }
}

注意我使用我想要的配置(prod或dev)定义的Inject [Messenger]如下所示:

object Inject extends Injector with DevConfig

trait ProdConfig {
  this: Injector =>
  register[Messager](new SkypeMessager)
  register[Messager](new ViberMessager, "viber")
}

trait DevConfig {
  this: Injector =>
  register[Messager](new ViberMessager)
  register[Messager](new ViberMessager, "viber")
}

最后这里是包含所有方法的Injector并注册:

class Injector {
  var map = Map[String, Any]()

  def apply[T: ClassTag] =
    map(classTag[T].toString).asInstanceOf[T]

  def apply[T: ClassTag](id: String) =
    map(classTag[T].toString + id).asInstanceOf[T]

  def register[T: ClassTag](instance: T, id: String = "") = {
    map += (classTag[T].toString + id -> instance)
    instance
  }
}

总结:

  • 我有一个类Injector,它是接口/ traits之间的Map(最终也是id)和实现的实例。
  • 我们为包含寄存器的每个配置(dev,prod ...)定义一个特征。它还有对Injector的自我引用。
  • 我们使用我们想要的配置
  • 创建一个Injector实例
  • 用法是调用apply方法给出Interface类型(最终也是id),它将返回实现的实例。

您怎么看?

3 个答案:

答案 0 :(得分:2)

您的代码看起来很像Lift Web框架中的依赖注入。您可以查阅Lift源代码以了解它是如何实现的,或者只是使用框架。您无需运行Lift应用程序即可使用其库。这是一个小介绍doc。基本上你应该在Lift中查看这段代码:

package net.liftweb.http

/**
 * A base trait for a Factory.  A Factory is both an Injector and
 * a collection of FactorMaker instances.  The FactoryMaker instances auto-register
 * with the Injector.  This provides both concrete Maker/Vender functionality as
 * well as Injector functionality.
 */
trait Factory extends SimpleInjector

您还可以查看以下相关问题:Scala - write unit tests for objects/singletons that extends a trait/class with DB connection,其中显示了如何使用Lift进样器。

答案 1 :(得分:0)

谢谢你们,

所以我做出了答案,但是Aleksey的答案非常好。

我更了解这个样本的蛋糕模式:
https://github.com/freekh/play-slick/tree/master/samples/play-slick-cake-sample
另请参阅其他没有DI的实现并进行比较:
https://github.com/freekh/play-slick/tree/master/samples/

所以蛋糕模式没有像我们所展示的升降式DI那样的集中配置。无论如何,我会使用Cake模式,因为它非常适合Slick 我对Subcut不喜欢的是各地的暗示。我知道有一种方法可以避免它们,但它看起来像是对我的修复。

由于

答案 2 :(得分:0)

要评论MacWire,你是对的,你可以使用new - 这就是重点:)。 MacWire只允许您从代码中删除一些样板,而不必再次枚举所有依赖项(已在构造函数中完成)。

主要的想法是你在“世界末日”进行布线,在那里组装你的应用程序(或者你可以把它分成特征模块,但这是可选的)。否则,您只需使用构造函数来表示依赖关系。没有魔法,没有框架。