DDD革命性在于,领域模型准确反映了业务语言,传统的J2EE或Spring+Mybatis等事务性编程模型只关心数据,这些数据对象除了简单setter/getter方法外,没有任何业务方法,被比喻为贫血模式。

事务脚本还是领域模型没有绝对的对错之分,CQRS就是对事务脚本和领域蘑菇型两种模式的综合,因为对于Query和报表的场景,使用领域模型往往会把简单的事情弄复杂。

对于简单的业务场景,使用事务脚本的优点是简单、直观、易上手。但对于复杂的业务场景,事务脚本就很难应付,容易造成代码一锅粥,系统的腐化速度和负责性呈指数上升。目前比较有效的治理方法便是领域建模,应为使用了通用语言,使得隐藏的业务逻辑得到显性化表达,是的复杂性治理成为可能。

举个例子
在事务脚本实现中,关于将一名学生升一年级的领域业务逻辑被写在了gradePromoteService的实现里面,而学生信息StudentInfo仅仅是getters和setters的数据结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class GradePromoteServiceImpl implements GradePromoteService{

private StudentInfoDao studentInfoDao;

@Override
public void gradePromote(Integer studentId, Integer grade) {
StudentInfo studentInfo = studentInfoDao.queryStudentInfo(studentId);

if(studentInfo.grade >= grade || grade > 6){
return;
}

studentInfo.setGrade(grade);
studentInfoDao.updateStudentInfo(studentInfo);
}

class StudentInfo{

private String name;

private Integer grade;

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getGrade() {
return grade;
}
public void setGrade(Integer grade) {
this.grade = grade;
}

}
}

上面的代码完全是面向过程的代码风格,同样的业务逻辑,如果用DDD来实现的话

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class GradePromoteServiceImpl implements GradePromoteService{

private StudentInfoDao studentInfoDao;

@Override
public void gradePromote(Integer studentId, Integer grade) {
StudentInfo studentInfo = studentInfoDao.queryStudentInfo(studentId);
studentInfo.gradePromote(grade);
studentInfoDao.updateStudentInfo(studentInfo);
}

class StudentInfo{

private String name;

private Integer grade;

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getGrade() {
return grade;
}
public void setGrade(Integer grade) {
this.grade = grade;
}

public void gradePromote(Integer grade){
if(this.grade >= grade || grade > 6){
return;
}
this.grade = grade;
}

}
}

原来在事务脚本中的逻辑,被分散到Domain Service,Domain Entity中去了

DDD最大的好处是:

  • 接触到需求第一步就是考虑领域模型,而不是将其切割成数据和行为,然后数据用数据库实现,行为使用服务实现,最后造成需求的首肢分离。DDD让你首先考虑的是业务语言,而不是数据。DDD强调业务抽象和面向对象编程,而不是过程式业务逻辑实现。重点不同导致编程世界观不同。
  • 同样,在面向对象的理论中,StudentInfo中的操作都封装在Entity上,提高了内聚性和可重用性。
  • 通用语言:“一个团队,一种语言”,这个很重要,将模型作为语言的支柱。确保团队在内部的所有交流中,代码中,画图,写东西,特别是讲话的时候都要使用这种语言。例如账号,转账,透支策略,这些都是非常重要的领域概念,如果这些命名都和我们日常讨论以及PRD中的描述保持一致,将会极大提升代码的可读性,减少认知成本。说到这,稍微吐槽一下我们有些工程师的英语水平,有些神翻译让一些核心领域概念变得面目全非。