項目架構規範:阿里規約,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<UserInfoDo main>{
@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<String> 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<String> addAuth(){
//根據sex獲取權限數據
return list;
}
}

 

用戶工廠代碼

 

@Component
public class UserInfoFactory implements BaseDomainFactory<UserIn foDomain>{

@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<String> 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<String> 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纔是業務實施者。 例如:餐廳中的服務員只是顧客和廚房之間的業務協調,服務員是知道做什麼的,服務員並不能決定菜怎麼做。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章