項目架構規範:阿里規約,MVC架構以及三層架構(二)

在實際開發中,經常會有Request/Response和Domain之間的互轉,會覺得毫無意義或太繁瑣,出現這種想法的主要原因是:Request和Domain 之間的屬性是一摸一樣,一個Object Copy代碼搞定。

 

列舉幾種在應用層創建Domain的方式

1. get/set方式

ProductUpdateDomain productUpateDomain= new ProductUpdateDomain();
productUpateDomain.setName(request.getName());
productUpateDomain.setSliders(request.getSliders());
productUpateDomain.setDescription(request.getDescription());

 

如果屬性夠多,會在應用層出現大量的對象轉換代碼

2. 屬性Copy方式

 ProductUpdateDomain productUpdateDomain = BeanUtils
.copyObject(p roductStateUpdateRequest, ProductUpdateDomain.class);


3. 構造函數方式

public class ProductDomain{
public ProductDomain(ProductRequest request) {
	……
	}
	public ProductDomain(ProductRequest request, String type) {
	……
	}
}


在不同的業務場景ProductDomain所需要的初始化參數是不同的,那就會定義多個構造函數,無法表達出真實的業務含義

 

OK,我們要理解一個重點,Domain是用來做業務的,所需要的屬性真的和Request的一摸一樣嗎?不用從其它地方獲取點做業務所需要的屬性?

@Transactional
public Long register(BusinessDomain businessDomain) {
//校驗手機號是否修改了
Object uuid = redisUtil.get(businessDomain.getPhone());
if (uuid == null) {
throw new BusinessException(BizErrorCode.ACCOUNT_WITHDOUT_CHECK);
	}
if (!uuid.toString().equals(businessDomain.getCode())) {
throw new BusinessException(BizErrorCode.ACCOUNT_WITHDOUT_CHECK);
	}
String[] categorys = businessDomain.getCategoryId().split(",");
if (categorys.length == 0) {
throw new BusinessException(BizErrorCode.REQUEST_PARAM_ILLEGAL);
	}
//傳進來的類目ID
Map<String, Object> cate = new HashMap<>();
cate.put("id", "," + businessDomain.getCategoryId() + ",");
//查找對應的類目ID信息
Map<String, String> categoryMap = new HashMap<>();
for (String id : categorys) {
TblCategories tblCategories = tblCategoriesRepository.get(Long.parseLong(id));
if (tblCategories == null) {
throw new BusinessException(BizErrorCode.REQUEST_PARAM_INVALID);
	}
	categoryMap.put(id, tblCategories.getName());
	}
cate.put("map", categoryMap);
businessDomain.setCategory(JsonUtil.toJson(cate));
businessDomain.setState(Constant.AUTH);

businessDomain.setCreateTime(new Date());
businessDomain.setUpdateTime(new Date());
//添加businessId
Long businessId = SeqGenerateUtil.getId();
businessDomain.setBusinessId(businessId);
/**保存商家信息*/
if (businessRepository.addBusiness(businessDomain) == 0) {
throw new BusinessException(BizErrorCode.ADD_BUSINESS_FAIL);
	}
//檢測商鋪名稱是否已經存在
if (businessStoreRepository.checkStoreName(businessDomain.getS toreName())) {
throw new BusinessException(BizErrorCode.STORE_NAME_EXIST);
	}
businessDomain.setCreateTime(new Date());
businessDomain.setUpdateTime(new Date());
if (businessStoreRepository.addBusinessStore(businessDomain) =
= 0) {
throw new BusinessException(BizErrorCode.ADD_BUSINESS_FAIL);
	}
//保存商家退貨信息
if (businessRefundAddressRepository.addBusinessRefund(business Domain) == 0) {
throw new BusinessException(BizErrorCode.UPDATE_INFO_FAILE);
	}
//保存商戶證書類信息
if (!businessAttrRepository.uploadUrl(list, businessDomain.get BusinessId())) {
throw new BusinessException(BizErrorCode.ADD_BUSINESS_FAIL);
	}
//先檢測該手機號是否已註冊
UserDomain userDomain = userServiceExternal.findByPhone(busine ssDomain.getPhone());
if (userDomain != null) {
userDomain.setOrganizeId(businessDomain.getBusinessId());
//更新用戶信息

Boolean flag = userServiceExternal.update(userDomain);
if (!flag) {
throw new BusinessException(BizErrorCode.UPDATE_INFO_FAILE);
	}
//保存userid到商家信息中
businessDomain.setUserId(userDomain.getId());
} else {
//如果未註冊商戶信息則註冊
UserInfoDomain userInfoDomain = new UserInfoDomain();
userInfoDomain.setMobile(businessDomain.getPhone());
userInfoDomain.setUserType(Constant.BUSINESS_USER);
userInfoDomain.setLoginName(Constant.USERNAME_PRE + businessDo main.getPhone());
userInfoDomain.setPwd(pwdUtils.getPwd(Constant.USER_PWD));
userInfoDomain.setStatus(Constant.NORMAL);
userInfoDomain.setOrganizeId(businessDomain.getBusinessId());
userDomain = userServiceExternal.addUser(userInfoDomain);
//保存userid到商家信息中
businessDomain.setUserId(userDomain.getUserId());
	}
if (businessRepository.updateUserId(businessDomain) == 0) {
throw new BusinessException(BizErrorCode.UPDATE_INFO_FAILE);
	}
	return businessDomain.getUserId();
	}

看看uuid 、categorys、setCategory,甚至如下代碼:

businessDomain.setCategory(JsonUtil.toJson(cate));
businessDomain.setState(Constant.AUTH);
businessDomain.setCreateTime(new Date());
businessDomain.setUpdateTime(new Date());
Long businessId = SeqGenerateUtil.getId();
businessDomain.setBusinessId(businessId);

首先uuid 、categorys、setCategory、setOrganizeId這些屬性的獲取都充斥在業務邏輯當中,但其實都是需要做業務的屬性,在初始化Domain的時候就該賦值的。

其次,CreateTime\UpdateTime是不屬於業務參數的,僅僅是爲數據庫操作賦值,是應該放在倉庫層來賦值。

如此這樣,Domain就不可能和Request一樣,不能用一條Copy代碼搞定了。

 

爲解決這個問題,在領域中推薦使用Factory Pattern(工廠模式),通過一個特定方法封裝了對象數據初始化的邏輯,而這個方法其實就是個普通的方法,因此可以自由的定義方法名,而不必像構造函數那樣受 限,所以可以自由的表達業務含義。

 

領域對象工廠(Domain Factory),用於複雜領域對象的創建/重建,重建是指通過respostory加載持久化對象後重建領域對象。有時創建一個Domain是一件比較複雜的事情,不僅僅是簡單的new操作或屬性複製操作,Factory就是用來封裝創建一個複雜對象的過程,將創建對象的細節隱藏起來。

 

改造後的代碼如下應用層API:

 

@RequestMapping(value = "/merchant/register",method = RequestMet hod.POST)
public ResultData register(@Valid AddUserRequest addUserRequest, BindingResult result) {
//1.參數校驗

//2.數據組裝
BusinessDomain businessDomain = businessFactory.compose(addUser Request);
//3.業務編排
userServiceImpl.register(businessDomain);
//4.參數響應
return ResultData.getSuccessResult();
}

 

在Domain.Factory加入BusinessFactory,代碼如下:

@Component
public class BusinessFactory implements BaseDomainFactory<Busine ssDomain>{
@Override
public BusinessDomain compose(Request request) {
BusinessDomain businessDomain = new BusinessDomain();

//UUID處理
Object uuid = redisUtil.get(request.getPhone());
businessDomain.setUuid("uuid");

//categorys處理
String[] categorys = request.getCategoryId().split(",");
businessDomain.setCategorys(categorys);

//Category處理
Map<String, Object> cate = new HashMap<>();
cate.put("id", "," + request.getCategoryId() + ",");
Map<String, String> categoryMap = new HashMap<>();
for (String id : categorys) {
TblCategories tblCategories = tblCategoriesRepository.get(Long.parseLong(id));
if (tblCategories == null) {
throw new BusinessException(BizErrorCode.REQUEST_PARAM_INVALID);
}
	categoryMap.put(id, tblCategories.getNam());
}

Service層的代碼如下:
public void register(BusinessDomain businessDomain) {
if (StringUtils.isEmpty(businessDomain.getUuid())) {
throw new BusinessException(BizErrorCode.ACCOUNT_WITHDOUT_CHECK);
}
if (!businessDomain.getUuid().toString().equals(businessDomain.getCo e())) {
throw new BusinessException(BizErrorCode.ACCOUNT_WITHDOUT_CHECK);
}
if (businessDomain.getCategorys().length == 0) {
throw new BusinessException(BizErrorCode.REQUEST_PARAM_ILLEGAL);
}
 
if (businessRepository.addBusiness(businessDomain) == 0) {
throw new BusinessException(BizErrorCode.ADD_BUSINESS_FAIL);
}
 
if (businessStoreRepository.checkStoreName(businessDomain.getS toreName())) {
throw new BusinessException(BizErrorCode.STORE_NAME_EXIST);
}
	//其它代碼
}

注意要點

 

1、在做業務之前把需要的業務屬性封裝好,不要在Service出現大量的業務屬性獲取、賦值的操作

2、Domain不能出現和業務無關的屬性,例如自增ID、創建信息、更新信息和其他業務無關的參數

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