DDD领域模型大纲总图的解读

补:最近看的ddd的东西越多,发现自己刚学DDD的内容越不准确,仅做自己学习的痕迹,不作为参考,怕有看的同学被误导!!!2012-3-30

-----

从DDD的概念的提出到现在,貌似今后一段时间DDD会火起来,于是乎,我学习了一下官方的例子,马丁同学及Evan同学的书,有所得,与大家共享。

本文适合新手,因为是DDD新手写的。

解读导航图

一说DDD,大家可能一下想到以下图(可能您老看的是E文版):

image

首先,上图是以Domain为中心,既然是领域驱动,肯定是以领域为中心,这是句废话。

,上图表示的是,domains包下面所包含的元素,这不好理解吧,咱们来个例子:

以春节回家为例子:

其领域模型大致如:

人可能坐多个交通工具,交通工具一般是一条线路,线程有是多个位置字移动。

image

比如咱们的包分层(此次不讨论包如何分层,以及test为何在这里):

image

我们一一解读图里的元素:

实体:这个很好理解,也要持久的元素,按DDD,实体的实现其实要更容易读,同时实现一些自身的简单逻辑,实体里没有get/set方法(方法1)(非充血,非贫血),如:

  1: public class Location extends IdEntity {
  2:   private LocationCode locationCode;
  3:   private String name;
  4: 
  5:   public Location(LocationCode locationCode, String name) {
  6:     Validate.notNull(locationCode);
  7:     Validate.notNull(name);
  8: 
  9:     this.locationCode = locationCode;
 10:     this.name = name;
 11:   }
 12: 
 13:   Location updateLocationName(String name) {  
 14:     //Some logic...
 15:     return new Location(locationCode, name);
 16:   }
 17: 
 18:   public LocationCode locationCode() {
 19:     return locationCode;
 20:   }
 21: 
 22:   public String name() {
 23:     return name;
 24:   }
 25: 
 26:   public final static Location UNKOWN = new Location(new LocationCode(1111, 222), "UNKOWN");
 27: 
 28:   Location() {
 29:     // needed for hibernate
 30:   }
 31: }

使用如下:

  1: Location location=new Location(new LocationCode(1222, 133), "ShenZhen");
  2:     location.updateLocationName("HK");
  3:     
  4:     int latitude = location.locationCode().latitude();

上面方法如何持久?有人会问,可以使用@Access(AccessType.FIELD)

还有一种实体的方法,在实体里有get/set,贫血型的,但有一个工厂方法去构造实体(方法2):

  1: public class LocationBuilder {
  2:   LocationCode locationCode;
  3:   String name;
  4: 
  5:   private LocationBuilder() {
  6:   }
  7: 
  8:   public static LocationBuilder newBuilder() {
  9:     return new LocationBuilder();
 10:   }
 11: 
 12:   public LocationBuilder at(int longitude, int latitude) {
 13:     locationCode = new LocationCode(longitude, latitude);
 14:     return this;
 15:   }
 16: 
 17:   public LocationBuilder withName(String name) {
 18:     this.name = name;
 19:     return this;
 20:   }
 21: 
 22:   public Location build() {
 23:     return new Location(locationCode, name);
 24:   }
 25: }

Builder的使用,这里使用了DSL的组织方式,使用者很容易明白程序的意思,也好维护使用,很有魅力。(Martin挺牛的)

  1: Location location1=LocationBuilder.newBuilder().at(122, 233).withName("ShenZhen").build();

值对象:值对象在领域里是很有用的,我认为它是组成模型的一部分,可以持久,也可以不持久,比如上例子中的LocationCode,它不持久,Location引用它后再持久。

仓库:表示数据来源,或者实现持久,它不仅仅是DAO,可能是远程接口,而在domains层,它只定义接口,在基础层实现,如

  1: public interface LocationRepository {
  2:   /**
  3:    * Finds a location using given locationCode.
  4:    * 
  5:    * @return Location.
  6:    */
  7:   Location find(LocationCode locationCode);
  8: 
  9:   /**
 10:    * Finds all locations.
 11:    * 
 12:    * @return All locations.
 13:    */
 14:   List<Location> findAll();
 15: }

工厂:用来产生实体,值对象,或者初始化等工作的,具体例子可以参考上面的例子。如果没有LocationBuilder的组装,用户使用起来可能比较困难,我认为它是简化用户的使用。

聚合:我认为,聚合是多个实体或者值对象组装成一个领域对象(称作Aggregate Root,它是老大,所以下面有很多小弟为它服务),其实它就是把一个大的模型拆分成各个大家都理解的小模型,如车,由轮子,车体,发动机等组成,这里的车就是一个聚合体。如例子里的Location.

服务:服务定义整个领域层对外提供的服务类,它仅在领域层定义,由基础层实现。如RoutingService,本例里最主要的是实现回家的服务。

分层:本次不讲,下次开讲。

每个对象的含义大致讲了一下,且有例子相伴,你有所收获不?

或者你有何不同的看法,不妨讨论一下?

posted on 2012-01-17 17:58  夏雨的天空  阅读(1245)  评论(1编辑  收藏  举报

导航