【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】領域驅動設計實踐 —— 一些問題及想法