1. 程式人生 > >【DDD】領域驅動設計實踐 —— 一些問題及想法

【DDD】領域驅動設計實踐 —— 一些問題及想法

val htm resp 驅動 this inf 容易出錯 查詢接口 過程

原文:【DDD】領域驅動設計實踐 —— 一些問題及想法

在社區系統的DDD實踐過程中,將遇到一些問題和產生的想法記錄下來,共討論。

本文為【DDD】系列文章中的其中一篇,其他內容可參考:使用領域驅動設計思想實現業務系統。

1、dto、model和entity之間的互相轉化

user interface層的dto、domian層的model、infrastructure層的entity之間的互相轉換,比較繁瑣,硬編碼容易出錯。

如果命名較為規範,則可以考慮交給一個公共服務完成自動轉換,約定俗成:dto和model為駝峰式命名,entity和數據庫表保持一致,使用小寫字母+下劃線形式,可以考慮編寫一個工具服務完成自動映射;

現實情況下,社區系統是一個遺留系統,代碼規範不佳,因此通用工具服務不可行。

2、repository的實現

針對不同的存儲介質建議有不同的repository impl,比如rdb使用mybatis實現的dao,mongo有自己的dao;這些dao均需要實現domain層的Repository接口;

對於redis,通常用做緩存,它會搭配主存(rdb、mongo)使用,這時候,可以有一個RepositoryImpl實現類來包裝 緩存/主存之間的增刪改查邏輯。

例如:

com.eco.domain.repository.IUserRepository

public interface IUserRepository {
	
	public UserInfo queryUserInfoByUserId(long userId);

}

  

@Repository
public class UserRepository implements IUserRepository {
	@Autowired
	private JedisCluster jedisCluster;

	@Autowired
	private UserMapper userMapper;

	@Autowired
	private UserRespostoryTranslator userRespostoryTranslator;

	@Override
	public UserInfo queryUserInfoByUserId(long userId) {		
		UserRedisBean userRedisBean =  this.queryUserRedisBeanByUserId(userId); 
		return this.userRespostoryTranslator.translateFromUserRedisBean(userRedisBean);
	}

	private UserRedisBean queryUserRedisBeanByUserId(long userId) {
		UserRedisBean userRedisBean = null;
		// 獲取緩存key
		String userIdKey = RedisKeyUtil.getRedisKey(RedisTypeEnum.UserInfoByUserId, StringUtil.toString(userId));
		String value = jedisCluster.get(userIdKey);

		// redis中不存在,則從db中獲取用戶相關信息
		if (StringUtil.isEmpty(value)) {

			// 根據userid及用戶社交對象從oracle查詢用戶信息
			userRedisBean = getUserRedisBeanFromOracle(userId);

			if (userRedisBean != null) {
				// 用戶信息寫入redis
				JedisClusterUtil.set(jedisCluster, userIdKey, JsonUtil.toJSONString(userRedisBean),ConfigurationConst.userRedisSeconds);
			}
		} else {
			// 如果redis中存在,則從redis獲取用戶相關信息,並設置有效期
			userRedisBean = JsonUtil.parseObject(value, UserRedisBean.class);
		}
		return userRedisBean;
	}

	/**
	 * 根據userid從oracle查詢用戶信息
	 * 
	 * @param userId
	 * @return UserRedisBean 欲存入redis中的用戶信息bean
	 */
	private UserRedisBean getUserRedisBeanFromOracle(long userId) {

		UserRedisBean userRedisBean = null;

		// 根據userid查詢用戶信息
		UserInfo userInfo = this.queryUserInfoByUserIdFromOracle(userId);

		//ignore transfer UserInfo to UserRedisBean.
return userRedisBean; }
}

3、查詢式和命令式接口使用的domain需要分離

查詢式接口domain應當簡化,甚至於去掉。通常查詢接口的實現邏輯為:入參校驗、鑒權、從Repository中獲取數據、拼湊不同的數據、數據轉換、返回數據。理論上,不應當存在過多的業務邏輯。所以可以淡化domain層。如果仍然按照:entity --> model -->dto的轉換路徑,實際model的作用沒有,反而帶來了代碼復雜度,不值得。

命令式接口,除去查詢式接口的邏輯,還有部分業務相關的,比如“關註”這一業務邏輯,較為復雜,需要收口到domain。

因此,建議如下處理方式:

  查詢式和命令式接口使用的domain需要分離設計,查詢式接口使用的domain可以淡化。

【DDD】領域驅動設計實踐 —— 一些問題及想法