在Ruby on Rails/Naked Objects精神指引下的域驱动开发框架

板桥里人 https://www.jdon.com 2005/07/15

  Ruby on Rails已经受到越来越多的重视,更多文章开始关注,Rolling with Ruby on Rails一文比较详细,也有国人做了翻译,按这里。这里我们不过多讨论ROR(Ruby on Rails),而是探讨如何以一个正确的方式快速开发J2EE。

现在的问题

  现在我们J2EE开发碰到了什么问题呢? 让我们想象一下使用Spring和Hibernate开发一个J2EE WEB应用是什么样的:我们需要增加一个新的域对象类型为Person,下面主要的开发步骤:

  1. 创建Person类.
  2. 创建PersonDAO类.
  3. 创建Person数据表.
  4. 定义PersonDAO在Spring的application context XML文件.
  5. 创建Person page页面和action类.
  6. 增加Person页面到web框架(如struts)XML配置文件中.
  7. 创建personList页面来显示Person实例.
  8. 创建personEdit页面来编辑Person实例.

  你会确实感慨:真是需要很多步骤啊。

如何解决?

  关键问题是我们开发时不能重复一些步骤,因此必须尽量减少步骤,如果只减少步骤到:

  1. 创建Person类?

  是否只需要第一个步骤就可以?在第一步时,我们花费更多时间精力进行域建模,确定域模型的属性行为等。其他步骤我们会发现下面的规律:

  • 对于每个实体,我们需要完成应用的基本功能,如 create, retrieve, update, and delete (CRUD).
  • 我们需要每个实体持久化到数据库.
  • 我们需要数据库为每个实体创建数据表。
  • 我们需要安排实体之间的关系。

  当然,在复杂应用中,不会只是这些功能,但是如果我们将这些功能通过框架实现,将大大提高我们的开发效率。

域驱动开发

  域驱动开发(domain driven development framework ),简称DDD是一种最新的OO设计概念,它是由ROR和Naked Object组织提出的。

  所谓naked Object是指一个复杂的域对象,这个Object是一个POJO,但是不是一个傻傻的完全是属性的POJO,而是封装了业务逻辑的POJO,注意这里是最大的区别,一般业务逻辑我们是通过另外的Service类来实现,然后在Service中封装的transaction script(Martin Fowler却称为贫血模型) , naked Object则是合并起来的(有的类似回归传统了,符合Martin Fowler审美观了),但是,这种纯OO是和SOA()思想矛盾的(Service-Oriented vs. Object-Oriented ),可见Adventures in SOA(puts the business logic in service-like methods instead of on the object, service method -> business method --> persistence method) )

  个人感觉整个软件好像一直在玩0或1的游戏,不过也许最复杂的体系就是来自最简单的抉择,如股票/汇市等投资领域也如此。

  naked Object提出现在J2EE开发和裸体对象DDD开发下的图:

  通过这张图我们可以看到,以前方式造成J2EE开发层次之间调用混乱,修改和拓展非常不方便,而在右边的DDD开发方式下,界面(边界)对象就是域对象就是持久化的实体BO,没有多余的Contorller或Action了。原来Domain层被服务层Service layer遮挡,在右图中,则Domain层直接暴露给前台了,所以Domain没有东西被遮盖,裸露了,称为Naked(裸露) Objects.

现在怎么办?

  ROR提倡的DDD方式引起了众多J2EE开发者的兴趣,在各大Java媒体正在引起广泛的讨论,但是ROR不是Java的,那么有无基于Java的DDD开发框架呢?

  目前有不少DDD开发框架正在诞生中,Jdon框架正是在ROR这种精神指引下的一款快速开源开发框架,Jdon框架1.2.2版本虽然不是一个完全意义上的Naked Object,基于Service-Oriented 架构,但是已经初步具备上图右边开发流程,具体可参考Jdon Sample的开发流程

  使用Jdon框架开发J2EE应用系统,最重要的一个前提是:设计好你的域对象,然后在将域对象复制到表现层,变成表现层的ActionForm/ModelForm;将域对象直接在持久层使用Hibernate/iBatis等持久化到数据库;如果使用EJB的实体Bean持久化技术,将无需实现建立数据表;应用系统部署时,J2EE容器将直接根据实体建立数据表,也可节省前面步骤中两个步骤。

  当然,目前Jdon框架是采取分离手法,遵循桥模式,将抽象和行为分离,每个域对象对应一个操作它的服务类或DAO类,服务类主要用来封装业务逻辑层,然后将业务Service作为一个业务组件暴露给表现层的Controller/Action类,而Controller/Action则无需代码,只要通过如下配置即可完成:

<model key="username" class="com.jdon.framework.samples.jpetstore.domain.Account">
  <actionForm name=
"accountForm"/> //指定边界类
  <handler>
    <service ref=
"accountService"> //指定某个业务接口
      <getMethod name=
"getAccount"/>
      <createMethod name=
"insertAccount"/> //业务接口的新增方法
      <updateMethod name=
"updateAccount"/> //业务接口的修改方法
      <deleteMethod name=
"deleteAccount"/>
    </service>
    </handler>
</model>

  通过上述配置,净化了上图中应用控制层(Application or Controller layer)和Domain Layer之间对应关系,变得有条理而且明晰。

  随着Naked Object 被越来越多人认识和应用成熟,Jdon框架也将转向支持另外一个纯OO流派Naked Object, 就象它同时支持POJO派和EJB派一样。

  在Jdon框架以后版本中,会很方便支持Naked Object,只要将上面配置文件指向Service去除,CRUD方法由Model自己实现,如下:

<model key="username" class="com.jdon.framework.samples.jpetstore.domain.Account">
  <actionForm name=
"accountForm"/> //指定边界类
  <handler>
   <!-- <service ref=
"accountService"> //指定某个业务接口 无需业务层,去除-->
      <getMethod name=
"getAccount"/>
      <createMethod name=
"insertAccount"/> //业务接口的新增方法
      <updateMethod name=
"updateAccount"/> //业务接口的修改方法
      <deleteMethod name=
"deleteAccount"/>
   <!--  </service> -->
  </handler>
</model>

参考文章:

面向对象与领域建模

Ruby on Rails and J2EE technical comparison

ValueObject和DTO模式的一些疑问

Jdon Framework的服务调用命令模式实现

国人最早开源IOC/AOP框架JdonFramework

DDD(Domain-Driven Design领域驱动设计)实战

Java项目开发中常见根本性认识误区

领域模型驱动设计(DDD)之模型提炼

更多快速开发讨论

更多DDD专题讨论

讨论