DDD领域模型大纲总图的解读
补:最近看的ddd的东西越多,发现自己刚学DDD的内容越不准确,仅做自己学习的痕迹,不作为参考,怕有看的同学被误导!!!2012-3-30
-----
从DDD的概念的提出到现在,貌似今后一段时间DDD会火起来,于是乎,我学习了一下官方的例子,马丁同学及Evan同学的书,有所得,与大家共享。
本文适合新手,因为是DDD新手写的。
解读导航图
一说DDD,大家可能一下想到以下图(可能您老看的是E文版):
首先,上图是以Domain为中心,既然是领域驱动,肯定是以领域为中心,这是句废话。
再,上图表示的是,domains包下面所包含的元素,这不好理解吧,咱们来个例子:
以春节回家为例子:
其领域模型大致如:
人可能坐多个交通工具,交通工具一般是一条线路,线程有是多个位置字移动。
比如咱们的包分层(此次不讨论包如何分层,以及test为何在这里):
我们一一解读图里的元素:
实体:这个很好理解,也要持久的元素,按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,本例里最主要的是实现回家的服务。
分层:本次不讲,下次开讲。
每个对象的含义大致讲了一下,且有例子相伴,你有所收获不?
或者你有何不同的看法,不妨讨论一下?