项目架构规范:阿里规约,MVC架构以及三层架构(三)

封装是面向对象的的第一大特性,属性私有化,根据提供的setter和getter方法来访问属性,隐藏具体属性和实现细节。

@Data
public class UserInfoDomain {
  private String name;
  private String IDCard;
}

 

行为变成简单的setter/getter方法了,一个UserInfo其实有很多行为,例如:新增、手机号是否黑名单、IDCard是否合法等,但是这些行为代码就写满了service方法。

领域模型定义为【结合了行为和数据的领域对象模型】,与Entity是明显不同的,Entity仅是存储在数据库中的数据的对象表示,而行为位于单独的类中。领域模型基础会分为失血模型、贫血模型、充血模型、胀血模型,下面一一列举:

 

失血模型

Domain Object只有属性的get/set方法的纯数据类,所有行为的业务逻辑完全由Service层来完成。

Request代码

 

@Data
public class UserInfoRequest {
private String name;
private String IDCard;
}

 


用户领域对象
@Data
public class UserInfoDomain {
private String name;
private String IDCard;
} }

 


应用层代码

 

@RestController
public class UserInfoController {

@Autowired
private UserInfoService userInfoService;

@PostMapping(/user)
public ResultData regist(UserInfoRequest request){
UserInfoDomain userInfoDomain = BeanUtils.copyObject(request , UserInfoDomain.class);
userInfoService.addUser(userInfoDomain);
return ResultData.getSuccess();
}

}


业务逻辑层代码

@Service
public class UserInfoService {

@Autowired
private UserInfoRepository userInfoRepository;

public UserInfoDomain get(String idCade) {
return userInfoRepository.get(idCade);
}

public void addUser(UserInfoDomain userInfoDomain) {

if (null != userInfoRepository.get(userInfoDomain.getIDCard())) {
throw new BusinessException(BizCode.IDCard_IS_EXIST);
}
//身份证号合法性校验
String IDStr = userInfoDomain.getIDCard();

if (IDStr.length() != 18) {
throw new BusinessException(BizCode.IDCard_ILLEGAL);
}

if (IDStr.length() == 18) {
Ai = IDStr.substring(0, 17);
} else if (IDStr.length() == 15) {
Ai = IDStr.substring(0, 6) + "19" + IDStr.substring(6, 15);
}

// 判断出生年月是否有效
String strYear = Ai.substring(6, 10);// 年份
String strMonth = Ai.substring(10, 12);// 月份
String strDay = Ai.substring(12, 14);// 日期

if (isDate(strYear + "‐" + strMonth + "‐" + strDay) == false)
{
log.info("身份证号:{} 日期不正确",IDStr);
throw new BusinessException(BizCode.IDCard_ILLEGAL);
}
	......
Date birthday = DateUtil.toDate(IDStr.substring(6, 14));//生日
String sex = IDStr.substring(IDStr.length() ‐2 , IDStr.le ngth() ‐1);//性别
int age = DateUtil.getAge(birthday);//年龄
userInfoDomain.setBirthday(birthday);
userInfoDomain.setSex(sex == 1 ? "M" : "F";);
userInfoDomain.setAge(age);
userInfoDomain.setStatus(INIT);

//注册限制校验
if(this.age < 18 || this.age > 80){
throw new BusinessException(BizCode.NOT_QUALIFIED);
}

if(this.sex.equals("F")){
throw new BusinessException(BizCode.NOT_QUALIFIED);
}
//添加用户
userInfoRepository.add(userInfoDomain);

}
}

 


仓储层代码

@Component
public class UserInfoRepository implements Repository{
@Override
public void add(UserInfoDomain model) {
UserInfoEntity userInfoEntity = new UserInfoEntity();
userInfoEntity.setIDCard(model.getIDCard());
	......
	userInfoMapper.insert(userInfoEntity);
}

@Override
public UserInfoDomain get(String idCard) {
UserInfoEntity userInfoEntity = userInfoMapper.get(idCard);
if(null == userInfoEntity){
return null;
}
UserInfoDomain model = new UserInfoDomain();
model.setName(userInfoEntity.getName());
model.setAge(userInfoEntity.getAge());
model.setSex(userInfoEntity.getSex());
model.setBirthday(userInfoEntity.getBirthdady());

}
}

 

以上就是大家常见的代码,Controller-->Service-->Repository-->Mapper, ProductService 中存在大量的所谓业务逻辑代码,其实业务逻辑可以分离出两部分:做什么(业务工作流)和怎么做(具体实现),

 

Service只实现做什么,怎么做是领域对象Domain的事,这就是Domain 的行为。

 

贫血模型

Domain中出现了【不依赖于持久化】的逻辑,分离了做什么、怎么做, 做什么就会放到Service层,怎么做放Domain。

用户领域对象

@Data
public class UserInfoDomain {
private String name;
private int age;
private String IDCard;
private Date birthday;
private String sex;
private String status;
private List authoritys;
//身份证号合法性校验
public boolean idCardCheck(){
	......
}
//注册校验
public boolean registCteck(){
if(this.age < 18 || this.age > 80){
return false;
}
if(this.sex.equals("F")){
return false;
}
return true;
}
//添加权限
public List addAuth(){
//根据sex获取权限数据
return list;
}
}

 

用户工厂代码

 

@Component
public class UserInfoFactory implements BaseDomainFactory{

@Override
public UserInfoDomain compose(Request request) {

UserInfoDomain userInfoDomain = new UserInfoDomain();
String cardNo = request.getIDCard();//身份证号
Date birthday = DateUtil.toDate(cardNo.substring(6, 14));//生日

String sex = cardNo.substring(cardNo.length() ‐2 , cardNo.l ength() ‐1);//性别
int age = DateUtil.getAge(birthday);//年龄

userInfoDomain.setBirthday(birthday);
userInfoDomain.setSex(sex == 1 ? "M" : "F";); userInfoDomain.setAge(age); userInfoDomain.setStatus(INIT);

return userInfoDomain;
}
}

 


业务逻辑层代码

@Service
public class UserInfoService {

@Autowired
private UserInfoRepository userInfoRepository;

public UserInfoDomain loadUserById(Long id) {

return userInfoRepository.loadUserById(id);

}

public void addUser(UserInfoDomain userInfoDomain) {

if (null != userInfoRepository.get(userInfoDomain.getIDCard())) {
throw new BusinessException(BizCode.IDCard_IS_EXIST);
}

//身份证号合法性校验
if(!userInfoDomain.idCardCheck()){
throw new BusinessException(BizCode.IDCard_ILLEGAL);
}
//注册限制校验
if(!userInfoDomain.registCteck()){
throw new BusinessException(BizCode.NOT_QUALIFIED);
}
//添加用户
userInfoRepository.add(userInfoDomain);

//添加权限
List authList = userInfoDomain.addAuth();
userAuthRepository.add(list);

}
}

idCardCheck、registCteck逻辑是属于UserInfoDomain的行为放在Domain中。UserInfoDomain、authList只是在UserInfoDomain中生成而已,并没有做持久化操作。

调用路径为Controller-->Service-->Domain/Repository-->Mapper

充血模型

 

同贫血模型的区别是:持久化是Domain行为的一部分,Service是很薄的一层,仅仅封装事务和少量逻辑,不和仓库层打交道。

用户领域对象

@Data
public class UserInfoDomain {

@Autowired
private UserInfoRepository userInfoRepository;

@Autowired
private UserAuthRepository userAuthRepository;

private String name;
private int age;
private String IDCard;
private Date birthday;
private String sex;
private String status;
private List authoritys;

//身份证号合法性校验
public boolean idCardCheck(){
	......
}

//注册校验
public boolean registCteck(){
if(this.age < 18 || this.age > 80){
return false;
}

if(this.sex.equals("F")){
return false;
}
	return true;
}

//添加权限
public void addAuth(){
//根据sex获取权限数据
userAuthRepository.add(list);
}

//添加用户
public void addUser(){
userInfoRepository.add(this);
}
}

 


业务逻辑代码
@Service
public class UserInfoService {

@Autowired
private UserInfoRepository userInfoRepository;

public UserInfoDomain loadUserById(Long id) {
return userInfoRepository.loadUserById(id);
}

public void addUser(UserInfoDomain userInfoDomain) {
if (null != userInfoRepository.get(userInfoDomain.getIDCard())) {
throw new BusinessException(BizCode.IDCard_IS_EXIST);
}

//身份证号合法性校验
if(!userInfoDomain.idCardCheck()){
throw new BusinessException(BizCode.IDCard_ILLEGAL);
}

//注册限制校验
if(!userInfoDomain.registCteck()){
throw new BusinessException(BizCode.NOT_QUALIFIED);
}

//添加用户
userInfoDomain.addUser();

//添加权限
userInfoDomain.addAuth();

}
}

 

调用路径为Controller-->Service-->Domain-->Repository-->Mapper 至此,Service只是做业务节点的编排,将对于数据库的操作变成了Domain行为的一部分了。

 

胀血模型

基于充血模型,可以认为Service已经毫无作用了,调用路径可以简化为Controller-->Domain-->Repository-->Mapper。

那就考虑一个问题,是否所有的业务逻辑都是Domain的行为?如果不是,那这些逻辑放哪里?

 

总结

我们用哪种?

失血模型和胀血模型一般是不推荐的,但是有一条是确定的:Service 只是业务的协调者,并不是业务的实施者,Domain才是业务实施者。 例如:餐厅中的服务员只是顾客和厨房之间的业务协调,服务员是知道做什么的,服务员并不能决定菜怎么做。

 

 

你可能感兴趣的:(java,代码规范,项目架构,设计模式,领域驱动开发)