论 IoC 的两种方式

前面讨论了 spring、guice 这类 IoC container,他们的基本思想就是 dependency injection:将“初始化”这个部分交由 container 来管理,程序员不考虑模块之间的依赖关系“怎么”满足,而只关心谁依赖于谁。

他们实现的策略无外于通过 XML 或者 annotation 表达 component 之间的依赖关系,然后 framework 本身完成 component 之间的嵌入、生存周期等等。IoC container 就像一个胶水,将整个程序里面需要的组建关联了起来。

然而通过 mixin 还存在第二种建立这类关系的策略,我们这里以 scala 的 cake pattern 为例进行比较。例子我们选择常见的一个 layer design, web service 中一般有层 persistent layer,之上是 DAO layer、然后是 business object、service layer。每层的对象理论上只应该与上层的“接口”打交道。比如我们选择 persistent layer 的实现为 hibernate,DAO layer 上对应接口的实现我们需要 SessionFactory(或者使用 contextual session 的话我们甚至可以理解成为需要一个函数返回 Session)。某个 BO 又可能需要几个 DAO,如此下去。那么通过 IoC container 实现 DAO 时,就会采用类似下面的策略:

public interface GenericDao<T, K> {
  T get(K k) ;
  // ...
}

public abstract class HibernateDao<T, K> implements GenericDao<T, K> {
  @Inject
  private SessionFactory factory ;

  public Session currentSession () {
    return factory.getCurrentSession () ;
  }

  // ... many more
}

这个符合大家对软件的层、类的直观感觉。实际上如果有 scala,程序的组织可能就是另外一个样子,因为 scala 可以使用另外的方式表达依赖关系。

trait HibernateSession {
  val factory: SessionFactory = _
  def session = factory.getCurrentSession
}

trait HibernateDao[T, K] extends GenericDao[T, K] { this: HibernateSession =>
  def get(k: K) (implicit m: Manifest[T]): K = session.get (k, m.runtimeClass.asInstanceOf[Class[T]])
}

这里 trait 之间的关系就足够表明两个 layer 之间的关系了,这意味着你可以

object MyApp extends SomeThing with HibernateSession with HibernateDao with ... {
  val factory = Factory.getInstanceFromConfig () ;
  // maybe more missing stuffs from other traits
}

事实上在测试或者什么的情况下,可以很容易的将某些实现换成 mock。这里每一级功能都是由上一级的 trait 提供的。不过需要小心的是因为 scala 做 linearization 的,同名的 case 会比较囧。scala 实现 DI 除了这个所谓 cake pattern 以外,还有 structural typing,这相当于利用 trait 作为接口,BO 直接在 trait 上面干活,接受一个 duck-typed 环境变量(包括所有 traits),具体用这个 BO 的时候提供包括实现的环境变量(也可以认为是配置)。类似的一个做法是把环境变量里面的成员设为 implicit 的,这样在某些环境下如果定义了这些实现,就可以自动的使用他们了,如在环境变量里面也通过 implicit 定义,并将其 import 到当前的 scope 里面。

当然并不是说 scala 这套并不能和 IoC container 协同工作,实际上使用 annotation 的 Guice 与 scala 的 structural typing 还是可以很容易一起工作的。参考这里

——————
And Jacob’s anger was kindled against Rachel: and he said, Am I in God’s stead, who hath withheld from thee the fruit of the womb?

Advertisements
论 IoC 的两种方式

一个有关“论 IoC 的两种方式”的想法

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s