赞
踩
概述
去年4月份入职后第一次了解到DDD,当时觉得很晦涩(现在来看应该是红皮书将战略设计放在前半部分的缘由)。今年4月份的时候想学学系统设计方面的知识,便开始静下心来好好研究了两个月,感觉收益颇多。
DDD是什么
DDD是一种'面向对象'的软件设计思想。
领域驱动设计DDD作为一种软件设计方式, 有利于创造一个可测试的、可伸缩的、组织良好的软件模型
贫血症与失忆症
写Java差不多刚好两年, 接触过的项目中,几乎所有的业务逻辑都是写在service里面,对象都只是数据持有器(POJO),这些没有任何业务方法的对象就是贫血对象。
在这样的系统中,代码里面往往充斥者大量与业务无关的getter、setter方法,开发人员会将将大量的精力放在数据映射上面,而不是真正有价值的对象行为。
下面是一个更新用户的例子:
public void updateUser(String userId, String firstName, String lastName, String mobile,String address, Integer sex, String avator, ...) {
User user = new User();
if(userId != null) {
user.setUserId(userId);
}
if(firstName != null){
user.setFirstName(firstName);
}
if(lastName != null){
user.setLastName(lastName);
}
if(mobile != null){
user.setMobile(mobile);
}
if(address != null){
user.setAddress(address);
}
if(sex != null){
user.setSex(sex);
}
if(avator != null){
user.setAvator(avator);
}
...
userDao.updateUser(user);
}
复制代码
首先:这个方法的业务意图不明确。应用层应该一个方法对应一个明确的业务用例,如更新用户手机号, 更新居住地址等。
其次:方法的实现增加了潜在的复杂性。 我们应该怎么测试这段代码呐?这么多if, 你确定你能愉快的修改代码吗,内心是不是很排斥?
最后:User对象只是一个数据持有器。
这种情况也被称为由贫血症导致的失忆症。
如何DDD
通用语言
通用语言是团队之间用于交流的语言,一般指当前业务场景提炼出来的领域术语、词组和句子。比如绩效系统里"271排名"就是一种领域术语。
限界上下文
限界上下文可以看成是整个应用程序之内的一个概念性边界。这个边界之内的每种领域术语、词组或句子 --- 也即通用语言,都有确定的上下文含义。而在边界之外,这些术语可能有不同的意思。
比如盘点,当HR说盘点时是对员工进行盘点;而IT说盘点的时候,是对设备进行盘点。两者的上下文是完全不一样的,盘点的语义自然不同。
以日程管理系统开始DDD学习
部分用例
企业员工发起一个日程,包含日程的主题、开始时间、结束时间、参与人员。
发起人修改日程时间
参与人确认日程
员工查看自己当天的所有日程
传统面向过程的写法
/**
创建日程:1.日程表中插入一条记录, 2.人关联日程
**/
@Transactional
public void createSchedule(String title, Date startTime, Date endTime, List participantIds){
Long sponsorId = loginUser.get().getUserId();
//创建日程
Schedule schedule = new Schedule();
schedule.setTitle(title);
schedule.setStartTime(startTime);
schedule.setEndTime(endTime);
schedule.setSponsorId(sponsorId);
Long scheduleId = scheduelDao.insert(schedule);
//人关联日程
List userSchedules = new LinkedList();
for(participantId : participantIds){
userSchedules.add(new UserSchedule(participantId, scheduleId, 0));
}
if(!userSchedules.isEmpty()){
userScheduleDao.batchInsert(userSchedules);
}
}
复制代码
这样写其实也暴露了底层数据结构
DDD写法
日程对象
public class Schedule{
private String title;
private Date startTime;
private Date endTime;
private User sponsor;
Set participants;
Set confirmUsers;
Set refuseUsers;
/**
通过构造函数创建一个日程
**/
pubulic Schedule(String title, Date startTime, Date endTime, User sponsor, Set participants){
if(title == null || title == ""){
throw new IllegalArgumentException("schedule title empty");
}
if(startTime == null || endTime == null || !startTime.before(endTime)){
throw new IllegalArgumentException("schedule time range invalid.");
}
if(sponsor == null){
throw new IllegalArgumentException("schedule sponsor not found");
}
//remove duplicate
participants = participants.strem().filter(participant -> !participant.equals(sponsor)).collecot(Collectors.toSet());
this.title = title;
this.startTime = startTime;
this.endTime = endTime;
this.participants = participants;
}
/**
更新日程时间
**/
void updateTimeRange(Date startTime, Date endTime){
if(startTime == null || endTime == null || !startTime.before(endTime)){
throw new IllegalArgumentException("schedule time range invalid.");
}
this.startTime = startTime;
this.endTime = endTime;
}
/**
日程确认
**/
void confirm(User participant){
if(!this.participants.contains(participant)){
throw new IllegalArgumentException("you are not invited, can`t confirm");
}
if(this.confirmUsers.contains(participant)){
throw new IllegalArgumentException("you have confirmed");
}
this.confirmUsers.add(participant);
}
}
复制代码
应用层 -- ApplicationService
/**
创建日程
**/
@Transactional
public void createSchedule(String title, Date startTime, Date endTime, List participantIds){
Long sponsorId = loginUser.get().getUserId();
User sponsor = useRepository.userOfId(sponsorId);
List participants = useRepository.usersOfIds(participantIds);
Schedule schedule = new Schedule(title, startTime, endTime, sponsor, participants);
scheduleRepository.add(schedule);
}
/**
更新日程时间
**/
@Transactional
public void updateScheduleTime(Long scheduleId, Date startTime, Date endTime){
Schedule schedule = scheduleRepository.scheduleOfId(scheduleId);
schedule.updateTimeRange(startTime, endTime);
scheduleRepository.save(schedule);
}
/**
确定日程
**/
@Transactional
public void confirmSchedule(Long scheduleId){
Long userId = loginUser.get().getUserId();
User user = useRepository.userOfId(userId);
Schedule schedule = scheduleRepository.scheduleOfId(scheduleId);
schedule.confirm(user);
scheduleRepository.save(schedule);
}
复制代码
The end
通过上面日程管理的demo,你是否可以重构updateUser方法呐?
关于找一找教程网
本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。
本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。
[DDD- 领域驱动设计入门]http://www.zyiz.net/tech/detail-139677.html
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。