DependencyInjectionInterceptor非常强大,每次从数据库中加载实体后它都能将在Spring中配置的服务注入其中。那如果我们在应用代码而非JAP等框架中实例化实体时又该怎么办呢?
自动装配“手工”实例化的领域对象
要想自动装配应用代码中实例化的实体,最简单也是最笨的办法就是通过RichDomainObjectFactory的方式显式进行自动装配。由于这个办法将RichDomainObjectFactory类与实体创建代码紧耦合起来,因此并不推荐使用。幸好,Scala提供了“组件对象”的概念,它担负起工厂的职责,可以灵活实现构造逻辑。
对于该示例应用,我们采用如下方式实现Person对象以便“自动”提供自动装配功能:
|
import声明会导入RichDomainObjectFactory的所有静态方法,其中的autoWireFactory()方法会处理RichDomainObjectFactory单例对象。
Scala对象另一个便利的构造手段就是apply()方法,其规则是拥有apply方法的任何对象在调用时可以省略掉.apply()。这样,Scala会将对Person()的调用转给Person.apply(),因此可以将自动装配代码放到apply()方法中。
这样,无需使用“new”关键字就可以调用Person()了,它会返回一个新的实体,返回前所有必要的服务都已经注入进去了,该实体也成为一个“富”DDD实体了。
现在我们可以使用富领域对象了,它是可持久化的,也能在需要时调用其中的服务:
|
在继续之前,我们需要解释一下为何要用Java而不是Scala来实现RichDomainObjectFactory,原因是由Scala处理static的方式造成的。Scala故意没有提供static关键字,因为static与复合的OO/函数式范式有冲突。Scala语言所提供的唯一一个静态特性就是对象,其在Java中的等价物就是单例。由于Scala缺少static方法,因此Spring没法通过上文介绍的factory-method属性获得RichDomainObjectFactory这样的工厂对象。这样,我们就没法将Spring的AutowireCapableBeanFactory直接注入到Person对象中了。因此,这里使用Java而非Scala来利用Spring的自动装配功能,它能彻底填充static鸿沟。
第三步:使用Scala traits打造功能完善的领域对象
到目前为止一切尚好,此外,Scala还为OO纯粹主义者提供了更多特性。使用DAO持久化实体与纯粹的OO理念有些许冲突。从广泛使用的DAO/Repository模式的角度来说,DAO只负责执行持久化操作,而实体则只维护其状态。但纯粹的OO对象不仅有状态,还要有行为。
上文介绍的实体是拥有服务的,这些服务封装了一些行为性职责,但持久化部分并不在其中。为什么不把所有的行为性和状态性职责都赋给实体呢,就像OO纯粹主义者所倡导的那样,让实体自己负责持久化操作。事实上,这是习惯问题。但使用Java很难以优雅的方式让实体自己去实现持久化操作。这种设计严重依赖于继承,因为持久化方法要在父类中实现。这种方式相当麻烦,也缺少灵活性。Java从概念上就缺少一个良好设计的根基,没法很好地实现这种逻辑。但Scala则不同,因为Scala有traits。