×

【Scala】Cake模式和依赖注入

96
JasonDing
2016.03.11 22:06* 字数 1395

依赖注入(Dependency Injection)和控制反转(Inversion of Control)

Dependency Injection & Inversion of Control是Martin Fowler在2004年所提出來的一个概念,Martin Fowler在这篇文章中指出,DI可以有三种形式来实现。这观念以后有Spring项目和Google实现出来,变成了Java Enterprise应用中不可或缺的一部分。

控制反转是一个重要的面向对象编程的法则来削减计算机程序的耦合问题。控制反转一般分为两个类型,依赖注入(Dependency Injection)和依赖查找(Dependency Lookup)。依赖注入应用广泛。

许多应用程序都是由两个或更多的类通过彼此的合作来实现业务逻辑,这使得每个对象都需要与其合作的对象(也就是它做依赖的对象)的引用。如果这个获取过程要靠自身实现,那么这将导致代码高度耦合并且难以测试。
应用控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用,传递给它。也可以说,依赖被注入到对象中。所以,控制反转是关于一个对象如何获取它所依赖的对象的引用——这个责任的反转。

IoC模式,系统中通过引入实现了IoC模式的IoC容器,即可由IoC容器来管理对象的生命周期、依赖关系等,从而使得应用程序的配置和依赖性规范与实际的应用程序代码分开。其中一个特点就是通过文本的配置文件进行应用程序组件间依赖关系的配置,而不用重新修改并编译具体的代码。
对于Java程序而言,IoC模式可以看做是工厂模式的升华,可以把IoC看做是一个大工厂,只不过大工厂要生成的对象都是在XML文件中给出定义的,然后利用Java的反射编程,根据XML中给出的类名生成相应的对象。从实现来看,IoC是把以前的工厂方法里写死的对象生成代码,改变为由XML文件来定义,也就是把工厂和对象生成这两者独立分隔开来,目的就是提高灵活性和可维护性。

Scala中的蛋糕模式(cake pattern)

依赖注入一般需要三个组成部分:

  1. 依赖消费者
  1. 依赖项的声明(依赖消费者需要的依赖项)
  2. 将对象引用或类型注入到依赖消费者的方法

蛋糕模式(cake pattern)是Scala实现依赖注入的方法之一,它利用Scala Mixin功能,让对象被创建时,才把相依的原件,透过Mixin的方式绑在一起。

蛋糕模式的组成部分:

  • 配置特质(Configuration Trait):该结构定义了用于注入的对象的抽象
    配置特质是对被依赖的组件提供层(the dependent component providers layers)的包装,它提供了根组件所依赖的行为和数据
  • 具体的配置特质(Concrete Configuration Traits):该结构定义了被依赖的结构具体是如何创建的,比如通过配置文件、数据库或者维护在内存的资源
  • 内容特质(Context Trait):该特质用于确定被载入的具体配置
  • 依赖组件(Dependent Component):该组件依赖于具体配置结构提供的对象

蛋糕模式的实际问题:

  • 将所依赖的对象配置给应用程序代码使得在运行时进行调整更换成为可能。这些配置信息由XML文件、数据库或者其他合适的文件提供
  • 确定具体的配置可以在工厂对象中进行

演示例子

Config特质定义了load方法和text值,load方法在实例化时将被执行,用于载入配置信息。
一个具体的配置类型定义为InMemoryConfig,它定义了具体的Config行为。

trait Config {
  load
  val text: String
  def load: Unit
}

trait InMemoryConfig extends Config {
  lazy val text = "Hello"
  def load = println("load: " + text)
}

Context特质用来表示蛋糕模式的内容对象,MyContext特质使用this子类型注解(self type annotation)指定Config类型将被混入到当前类或对象中,于是Config特质中的数据和方法就好像是定义在该特质中的一样。
注意,多个特质都可以被混入到this引用中,比如this: ConfigContext with DAOContext with ConnectionManagerContext

trait Context

trait MyContext extends Context {
  this: Config =>
  def welcome = this.text
}

Env这个对象是单例模式在Scala中的语法化表示,它继承了混入InMemoryConfig特质的MyContext,它很好的表示了依赖嵌入环境。

object Env extends MyContext with InMemoryConfig

执行println(Env.text)将打印:

load: Hello
Hello

蛋糕模式的优缺点

优点

  1. 没有使用框架,仅使用语言特性
  2. 类型安全——缺失的依赖项在编译时被发现
  3. 功能强大——通过实现合适的依赖提供方法进行协助嵌入
    缺点是代码模板复杂

参考资料

Dependency Injection in Scala

转载请注明作者Jason Ding及其出处
jasonding.top
Github博客主页(http://blog.jasonding.top/)
CSDN博客(http://blog.csdn.net/jasonding1354)
简书主页(http://www.jianshu.com/users/2bd9b48f6ea8/latest_articles)
Google搜索jasonding1354进入我的博客主页

Scala
Web note ad 1