• DDD—Repository仓储&工厂模式


      一、解耦领域层和基础层       

              DDD严格的分层架构告诉我们,每一层只能与其下方的一层发生耦合。因此用户接口层只与应用层发生交互,应用层往下只与领域层发生交互,领域层往下只与基础层发生交互。

        在传统的代码分层结构Controller—Service—Dao结构中,经常能看到在Service业务实现层的代码中嵌入SQL,或者在其中频繁出现修改数据对象并调用DAO的情况。这样,基础层的数据处理逻辑就渗透到了业务逻辑代码中。

        在DDD的分层结构中,如果出现上述情况,则基础层的数据处理逻辑就渗透到了领域层,领域层中的领域模型就难以聚焦在业务逻辑上,对外层的基础层产生了依赖。而一旦涉及到数据逻辑的修改,就要到领域层中去修改代码,重新调试领域层与基础层的交互,或者当切换异构数据库类型时,需要大量修改领域层的代码,将业务逻辑和数据处理逻辑重新适配(主要在于异构数据库导致的SQL或数据对象调整),因此技术升级会变得特别麻烦。

        本文要讲的仓储模式就是用来解耦领域层和基础层的,降低他们之间的耦合和相互影响

        

      二、仓储模式

           为了解耦领域逻辑和数据处理逻辑,在中间加了薄薄的一层仓储。

        仓储模式包含仓储接口和仓储实现,仓储接口面向领域层提供基础层数据处理相关的接口,仓储实现则完成仓储接口对应的数据持久化相关的逻辑处理。一个聚合配备一个仓储,由仓储完成聚合数据的持久化。领域层逻辑面向仓储接口编程,聚合内的数据持久化过程为DO(领域对象)转PO(持久化对象)。

        当需要更换数据库类型,或者更改数据处理逻辑时,我们就可以保持业务逻辑接口不动,只修改仓储实现,保证了领域层业务逻辑的干净和纯洁。

        如下示例为一个人员聚合中对人员实体的仓储模式实现:

        人员DO和人员PO定义:  

    1. /**
    2. * 人员聚合
    3. * @author test11
    4. */
    5. public class Person {
    6. //人员id
    7. private String id;
    8. //姓名
    9. private String name;
    10. //地址(值对象)
    11. private Address address;
    12. //上班行为
    13. private void goWork(){
    14. }
    15. //下班行为
    16. private void leaveWork(){
    17. }
    18. public String getId() {
    19. return id;
    20. }
    21. public void setId(String id) {
    22. this.id = id;
    23. }
    24. public String getName() {
    25. return name;
    26. }
    27. public void setName(String name) {
    28. this.name = name;
    29. }
    30. public Address getAddress() {
    31. return address;
    32. }
    33. public void setAddress(Address address) {
    34. this.address = address;
    35. }
    36. }

    1. /**
    2. * 人员聚合的持久化PO
    3. * @author test11
    4. */
    5. public class PersonPO {
    6. //人员id
    7. private String id;
    8. //姓名
    9. private String name;
    10. //地址
    11. private Address address;
    12. public String getId() {
    13. return id;
    14. }
    15. public void setId(String id) {
    16. this.id = id;
    17. }
    18. public String getName() {
    19. return name;
    20. }
    21. public void setName(String name) {
    22. this.name = name;
    23. }
    24. public Address getAddress() {
    25. return address;
    26. }
    27. public void setAddress(Address address) {
    28. this.address = address;
    29. }
    30. }

    1. /**
    2. * 地址值对象
    3. */
    4. public class Address {
    5. //省份
    6. private String province;
    7. //城市
    8. private String city;
    9. //街道
    10. private String street;
    11. }

        仓储接口定义:

    1. /**
    2. * 人员聚合仓储接口
    3. * @author test11
    4. */
    5. public interface PersonRepository {
    6. /**
    7. * 添加人员
    8. */
    9. void addPerson(PersonPO personPO);
    10. /**
    11. * 更新人员
    12. */
    13. void updatePerson(PersonPO personPO);
    14. /**
    15. * 根据id查找人员PO对象
    16. * @return
    17. */
    18. PersonPO findById(String id);
    19. }

        

        仓储接口实现:

    1. /**
    2. * 人员仓储实现
    3. * @author test11
    4. */
    5. public class PersonRepositoryImpl implements PersonRepository{
    6. @Resource
    7. PersonDao personDao;
    8. @Override
    9. public void addPerson(PersonPO personPO) {
    10. personDao.addPerson(personPO);
    11. }
    12. @Override
    13. public void updatePerson(PersonPO personPO) {
    14. personDao.updatePerson(personPO);
    15. }
    16. @Override
    17. public PersonPO findById(String id) {
    18. return personDao.findById(id);
    19. }
    20. }

        

        人员领域服务实现:后面基础层发生了变化,则领域层无需动任何代码,只要仓储接口不变,领域层的逻辑就可以一直保持不变,维护了领域层的稳定性。领域服务是可以做成企业级可复用的服务的,因此稳定性必须有保障。

    1. import javax.annotation.Resource;
    2. /**
    3. * 人员领域服务聚合类
    4. * @author test11
    5. */
    6. public class PersonDomainService {
    7. @Resource
    8. PersonRepository personRepository;
    9. public void addPerson(PersonPO personPO) {
    10. personRepository.addPerson(personPO);
    11. }
    12. }

     

      三、工厂模式

      DO对象创建时,需要确保聚合根和它依赖的对象同时被创建,如果这项工作交给聚合根来实现,则聚合根的构造函数将变得异常庞大,所以我们把通用的初始化DO的逻辑,放到工厂中去实现,通过工厂模式封装聚合内复杂对象的创建过程,完成聚合根,实体和值对象的创建。DO对象创建时,通过仓储从数据库中获取PO对象,通过工厂完成PO到DO的转换

      工厂中还可以包含DO到PO对象的转换过程,方便完成数据的持久化。

    1. /**
    2. * Person聚合的工厂
    3. * DO和PO的转换
    4. * @author test11
    5. */
    6. public class PersonFactory {
    7. /**
    8. * 人员PO到领域对象的数据初始化
    9. * @param personPO
    10. * @return
    11. */
    12. protected Person createPerson(PersonPO personPO){
    13. Person person = new Person();
    14. person.setId(personPO.getId());
    15. person.setName(personPO.getName());
    16. person.setAddress(personPO.getAddress());
    17. return person;
    18. }
    19. /**
    20. * 领域对象到持久化对象PO的转换
    21. * @param person
    22. * @return
    23. */
    24. protected PersonPO createPersonPO(Person person){
    25. PersonPO personPO = new PersonPO();
    26. personPO.setId(person.getId());
    27. personPO.setName(person.getName());
    28. personPO.setAddress(person.getAddress());
    29. return personPO;
    30. }
    31. }

      

     

  • 相关阅读:
    Adobe Audition 入门系列(合集)
    【网络安全】-网络安全的分类详解
    LocalStroage,SessionStroage,Cookide,IndexedDB
    力扣第1488题——避免洪水泛滥
    Hive-DDL-常用操作命令(数据库操作、表操作、分区操作、show语法)
    大数据导论 笔记
    【Gradle】二、全新项目构建工具Gradle的体验
    android-handler
    使用 CRD 开启您的 Ingress 可观测之路
    【docker】Docker网络与iptables
  • 原文地址:https://blog.csdn.net/a6636656/article/details/126013493