你怎么做没有硬编码Cake模式的dependency injection?

我只是阅读和享受蛋糕模式的文章 。 然而,在我看来,使用dependency injection的关键原因之一是可以改变XML文件或命令行参数所使用的组件。

DI的这个方面是如何处理Cake模式的? 我见过的例子都涉及静态混合特征。

由于在Scala中混合性状是静态完成的,如果你想改变混合到一个对象的特征,根据某些条件创build不同的对象。

我们来看一个典型的蛋糕模式的例子。 你的模块被定义为特征,你的应用程序被构造成一个简单的对象,并且混合了一堆function

val application = new Object extends Communications with Parsing with Persistence with Logging with ProductionDataSource application.startup 

现在,所有这些模块都有很好的自定义声明,它们定义了它们之间的模块间依赖关系,因此只有在所有模块间依赖关系存在,唯一性和良好types的情况下,行才会进行编译。 特别是,持久性模块有一个自我types,它说什么实现持久性还必须实现数据源,一个抽象的模块特质。 由于ProductionDataSource是从DataSourceinheritance的,所以一切都很好,而且这个应用程序的构build线也在编译。

但是如果你想使用不同的数据源,指向某个本地数据库进行testing呢? 进一步假设你不能只重复使用具有不同configuration参数的ProductionDataSource,这些configuration参数是从一些属性文件加载的。 在这种情况下,你会做什么是定义一个新的特质TestDataSource,它扩展了DataSource,而不是混合它。 你甚至可以根据命令行标志dynamic地进行操作。

 val application = if (test) new Object extends Communications with Parsing with Persistence with Logging with TestDataSource else new Object extends Communications with Parsing with Persistence with Logging with ProductionDataSource application.startup 

现在看起来比我们想要的更加冗长,特别是如果您的应用程序需要改变其在多个轴上的结构。 另外一方面,通常情况下,你只有一个条件构build逻辑块,就像应用程序中的那样(或者每个可识别的组件生命周期最差一次),所以至less把痛苦减到最小,并且与其他逻辑隔离开来。

Scala也是一个脚本语言。 所以你的configurationXML可以是一个Scala脚本。 这是types安全的,而不是一个不同的语言。

简单的看一下启动:

 scala -cp first.jar:second.jar startupScript.scala 

和以下不一样:

 java -cp first.jar:second.jar com.example.MyMainClass context.xml 

您始终可以使用DI,但是您还有一个工具。

简单的答案是,斯卡拉目前没有任何内置的dynamic混合支持。

我正在使用autoproxy-plugin来支持这个function,尽pipe目前这个function已经暂时搁置了,直到2.9版本发布时,编译器才会有新function,这使得它变得更容易。

同时,实现几乎完全相同的function的最好方法是将dynamic添加的行为实现为包装类,然后将隐式转换添加回包装的成员。

在AutoProxy插件变得可用之前,达到这种效果的一种方法是使用委托:

 trait Module { def foo: Int } trait DelegatedModule extends Module { var delegate: Module = _ def foo = delegate.foo } class Impl extends Module { def foo = 1 } // later val composed: Module with ... with ... = new DelegatedModule with ... with ... composed.delegate = choose() // choose is linear in the number of `Module` implementations 

但要小心,这样做的缺点是它比较冗长,如果你在一个trait里面使用vars,你必须小心初始化顺序。 另一个缺点是,如果在上面的Module有path依赖types,那么您将无法轻松使用委派。

但是,如果有大量不同的实现可以改变,那么与列举具有所有可能组合的情况相比,它可能会花费更less的代码。

Lift有一些内置的东西。它主要是在scala代码中,但是你有一些运行时控制。 http://www.assembla.com/wiki/show/liftweb/Dependency_Injection