领域模型驱动( Domain Driven Design ),很热的名词。 Openfans ,不太热的网站。今天俺就借着很热的 ddd ,给不太热的 openfans 再造点势。 Openfans 就不多介绍了,网站用 spring+hibernate 为核心的一堆开源软件构建。有了 spring 的 IOC 和 hibernate 的 ORM ,打着 ddd 的旗号也就名正言顺了很多。先声明其实俺对 ddd 的理解也多是道听途说,没有什么系统的学习过,倒是和 Joe 阿牛讨论过几次,颇有受益,他对这个理解还是很深刻的。
言归正传,就讲 openfans 现在经 ddd 思想改造过的模型。整体上看还是普通的三层架构体系:展现层、业务层、持久层。展现层用 spring mvc ,力图做到只是展示相关,避免出现业务逻辑。再具体细分,就是 jsp 页面只有展示逻辑,主要使用 jstl 完成显示功能。 Controller 负责从页面获得参数、把数据传回页面、控制页面流传和调用业务层的接口。持久层使用 hibernate ,在设计上我不是按 dao 方式为每个对象建立相应的 dao ,也不是 ddd 推荐的每个 domain 一个 repository ,而是分成了 Persistence 和 Fetcher2 个接口。 Persistence 处理持久相关如 save 和 remove 方法, Fetcher 则处理 get 相关。这样分的原因也很简单, persistence 是很稳固的,对象都可以共用一个接口如 save ( Object ),而 fetcher 就千变万化,需要分页、排序等接口。
这样设计是与业务层架构相关的。我采用的是 domain 对象(简称 DO ) + 一层薄薄 façade 的方式。 DO 处理自身的逻辑,包括持久功能。本身 DO 是没有持久能力的,需要依靠注入的 persistence 接口,这里就体现按 Persistence 和 Fetcher 分开的一个好处, persistence 所有 DO 可以共用一个,给编程带来了方便。 Openfans 中采用的是 DO 继承一个抽象 PersistentObject 类的方式,这样 DO 方便的获得了注入的能力和持久的能力。这样做有何优缺点还需要做些讨论,为了方便我也就先这么用。 PersistentObject 代码如下:
public abstract class PersistentObject implements NeedPersist {
private Persistence persistence;
<!----> <o:p> </o:p>
public void save() {
persistence.save(this);
<o:p> </o:p>
}
<o:p> </o:p>
public void remove() {
persistence.remove(this);
}
<o:p> </o:p>
public void setPersistence(Persistence persistence) {
this.persistence = persistence;
}
<o:p> </o:p>
public Persistence getPersistence() {
return persistence;
}
}
这样 DO 只需要注入 persistence 就获得了持久的能力,而且可以把这种能力往下传递。 DO 获得了持久能力,就有点接近富血模型的想法了,他能够处理一些业务,做持久然后调用引用对象的业务和持久方法 ( 从另外的角度看持久与业务其实是分不开的 ) 。这样把业务封装在了领域本身,更适于用领域对象出发的方式去思考问题。领域层的 façade 主要是为了 Transaction 管理和隐藏 DO 接口。这样 DO 的业务方法都可以设置成 friendly ,仅相互间可见。 Façade 就放在 domain 包中,它负责给 DO 注入 persistence bean ,调用 DO 的接口,提供给 controller 一个 use case 级别的接口,同时它也代理 fetcher 的接口。
有了这个架构,实现起来也不复杂,要配置的 bean 很少(现在还没有使用 spring 2.0 将 DO 配置在容器中)。设计就从 DO 出发,明确它的属性和方法,让 hibernate 自己生成数据库表。
这样设计也算是一次尝试吧,其中肯定有很多考虑不周的地方,需要不断的讨论和改进。