• Jerry.hu
    2019-10-28
    老师能否结合一个实战的小项目进行讲解和梳理、同时可以将其项目贡享在git上 让大家结合实战 感觉效果会更好

    作者回复: 等我有时间的时候准备一下哈。现在的代码都是到类和方法级。

     3
     14
  • 约书亚
    2019-10-29
    请问,最后图中MapperXML是什么?是mybatis那种做对象和数据库字段映射的xml文件么?如果是,那其中包含了与业务逻辑无关的数据库具体实现,放在领域层是否不太合适?

    作者回复: 是Mybatis的映射文件。
    关于仓储,我是这么考虑的。仓储本身是属于基础层,但是考虑到一个聚合对应一个仓储,为了以后聚合代码整体迁移的方便,我在微服务代码目录设计时,在聚合目录下增加了一个Repository的仓储目录,跟仓储相关的代码都在这个目录下。
    这个目录下的代码与聚合的其它业务代码是分开的。如果未来换数据库的话,只需要将Repository目录下的代码替换就可以了。而如果聚合需要整体迁移到其它微服务中去,仓储的代码也会一并迁移。

     1
     4
  • FIGNT
    2019-10-28
    对层级的依赖倒置不太理解。好像还有个防腐层的概念。不知道能解释下吗

    作者回复: 依赖倒置举个例子,领域层是通过仓储接口获取基础资源的数据对象,仓储接口会调用仓储实现,具体的基础资源的数据处理过程是在仓储实现中完成的。这样做的好处是,避免将仓储实现的代码混入上层业务逻辑中。如果以后替换数据库,由于做了基础资源的个性的代码隔离,所以实现了应用逻辑与基础资源的解耦。在更换数据库时只需要更换仓储相关的代码就可以了,应用的逻辑不会受太大的影响。
    防腐层我感觉主要是实现新旧系统切换时,出现业务逻辑混杂在一起的情况,避免污染领域模型的实现逻辑。因此增加防腐层隔离旧系统对领域模型的影响。在完成新旧切换后,防腐层的代码就可以抛弃不用了。

     4
     4
  • LY
    2019-10-28
    对今天的思考题不太理解,领域对象不应该是放在领悟层么,应用层只是会重建这些领域对象而已,所以应用层应该不会写领域对象的类才对。那又何来应用层有哪些对象的问题呢?

    作者回复: 领域对象的概念比较广泛,除了实体、值对象和聚合根外,服务也算是领域对象。领域层和应用分别有领域服务和应用服务。

     1
     4
  • 祥敏
    2019-11-06
    您好,根据三层架构和DDD四层架构映射这张图,以SSM框架组合谈谈我的理解和问题:
    1.三层架构的业务接口层、业务逻辑层、数据访问层,对应实际开发的controller、service和dao三层;
    2.图中三层架构中业务逻辑层的VO对应为四层架构中用户接口层的DTO,我的理解是VO原本就在三层架构的用户接口层,在三层架构中也会用DTO竖向穿透三层简化开发。图中的DTO划分为用户接口层,实际只是VO。
    3.业务逻辑层中的service拆分为四层架构中的application service和domain service两层,如果以常见的CRUD开发来讲,domain service和applicatioin service是否在简单场景中就重叠了?
    4.三层开发中的仓储的依赖倒置已经实现了,mybatis层仓储接口被service层调用,mapper xml作为仓储的接口实现。如果采用DDD四层划分,mapper xml会被划分到基础层。repository aop这里的界面截指的是什么,是指ORM框架内部的bean与关系数据库实体之间的关系映射吗?
    5.聚合跟关注实体的持久化:聚合根、实体采用充血模型开发,CRUD中的CUD都会在聚合根、实体中实现,domain service 实现查询功能以及调用充血模型中的CUD方法,这样理解对吗?
    展开

    作者回复:
    第一,可以这么理解。
    第二,从本质来讲,DTO与VO都是对象。但是在DDD中将值传递的界限划分更细,比如DTO、DO、VO、PO,分别对应不同阶段的事务处理。DTO通常面向接口层,与VO相比可能会有前端应用/接口请求方要求的一些个性化的属性或值的映射等。
    第三,简单部分可能会有重叠,但是基于不对外暴露领域层逻辑的目的,会将实体方法封装成领域服务,领域服务再封装为应用服务,然后对外暴露。
    第四,这层本身是公共类,表示部分持久化的功能被提取为公共的面向切面聚合方法来实现
    第五,是这样的。实体值对象的数据逻辑通过聚合根来管理,多实体的业务行为通过领域服务来组合。

    
     2
  • 密码123456
    2019-10-28
    感觉用户接口层,存在感好低。仅仅存在调用应用层。 为什么还要存在这个层级?是因为,需要限制用户接口的访问?

    作者回复: 用户接口层也很重要啊,主要前后端调用的适配。如果你的微服务要面向很多的应用或渠道提供服务,而每个渠道的入参和出参都不一样,你不太可能开发出太多的应用服务,这样Facade接口就起很好的作用了,包括DO和DTO对象的组装和转换等。

     3
     2
  • 北极光
    2019-12-23
    老师,我有两个问题:
    1.基础服务 如果碰到工具类,还可以勉强放里面,但是静态扩展类就不行了,因为最新框架领域才是最低层。那么这种静态扩展类怎么放好呢?或则说怎么处理?

    2.领域的实体,虽然说是充血模型,但是实体里面的某个方法,很可能会细分很多业务类,甚至用到设计模式,比如用工厂。那么这些由实体的某一个方法细分开来的实现类,应该放在哪里?还是放在领域层吗?如果放在领域层,有什么好的方式区分他跟实体的区别呢?比如实体我放在entity文件夹下面,这些放在哪个文件夹下面呢?实体调用这些类,是直接new呢?还是这些类也用接口?

    作者回复: 不好意思哈,没看太懂,能否举个例子说明一下。

    
     1
  • Jerry银银
    2019-12-17
    请教老师:解耦各层对基础层依赖,采用依赖倒置的方式?这有点抽象,不知道是通过什么的一种方法?

    作者回复: 给你看一个非常简单的例子,有Person聚合根,Person聚合包括仓储接口和仓储实现。
    通过增加仓储服务,使得应用逻辑和数据库逻辑的依赖关系剥离,当换数据库的时候,只需要将仓储实现替换就可以了,这样不会对核心的业务逻辑产生影响。

    /**
     * Person聚合根
     */
    public class Person{
      private String id;
      private String name;
      private int age;
      private boolean gender;

    /**
     * 其它方法
     */
    }

    /**
     * Person仓储接口
     */
    public interface PersonRepositoryInterface {
      void save(Person person);
      void delete(String id);
     }

    /**
     *Person仓储实现
     */
    @Repository
    public class PersonRepositoryImp implements PersonRepositoryInterface {
      private PersonMapper mapper;
      public void save( Person person) {
          mapper.create(person);
      }
      public void delete((String id) {
        mapper.delete(id);
      }
     }

    在应用逻辑中直接用仓储的接口就可以了,数据库相关的逻辑在PersonMapper里面实现。
    PersonRepositoryInterface personRepos;
    personRepos.save(person)

     3
     1
  • 鲲哥
    2019-12-08
    欧老师,你好。问一个具体实现上的问题。充血模型的实体如果需要持久化,是直接调用repository还是由领域服务调用?如果直接调用,那在spring是如何实现的呢?sprign中repository一般单例bean,充血应该不是单例吧?那他是如何依赖repository的呢?

    作者回复: 一般都是通过应用服务或者领域服务来完成仓储调用,实体或聚合根作为参数传入仓储接口,通过仓储实现来完成持久化。一个简单的例子如下:

    public class OrderService {
    private OrderRepository orderRepository;
    public Order updateOrder(order) {
    ***;
    orderRepository.save(order);
    ***;
    }
    }

    
     1
  • TL
    2019-12-06
    老师好,可以具体讲讲domain层的service和application层service的区别吗,什么东西该房domian,什么该放application的service,然后application层app和aplication层的service具体又该如何界定,现在有点云里雾里,有点傻傻分不清楚

    作者回复: 我们先从底下往上逐层讲,单个实体自身的方法就是实体本身的业务行为。多个实体可组成更复杂的业务动作,这个是领域服务,实体的方法和领域服务共同构成领域模型的基础业务能力,这个能力是原子的基础的,不太考虑外界的用户行为和流程。而应用服务是对这些基础的能力进行组合和编排,它组合和编排的服务可以是跨聚合的领域服务,主要体现组合后的业务能力,更面向前端的用户操作,属于比较粗粒度的服务,通过编排可以更灵活应对外部需求变化。

    
     1
  • Geek_4660f3
    2019-11-28
    老师您好!
    我还有几个疑问:
    1、领域层和基础层的关系和传统三层架构中service和dao的区别在哪里,感觉没什么区别
    2、领域层和基础层的依赖倒置是不是就是通过增加仓库接口来实现的,让领域层依赖仓库接口和基础层对仓库接口依赖并且实现接口。具体跟仓库接口放在什么位置无关
    3、仓库接口放在领域层方便一起打包带走,但是仓库具体的实现在基础层,领域层打包带走那仓库具体实现咋办
    4、微服务拆分的时候领域层跟基础层一般是放在一个工程下面的么
    展开

    作者回复: 1、差异很大的,三层架构没有领域模型的概念,业务逻辑混杂在一起。DAO也是没有严格区分应用逻辑和基础资源逻辑的。
    2、是的。
    3、在目录结构里,仓储接口和实现都在聚合目录里面。
    4、这四层都是在一个微服务工程里面。

    
     1
  • 瓜瓜
    2019-11-13
    作者回复: 依赖倒置后基础层就通过仓储接口获取外部参数了,然后根据这些业务参数完成基础逻辑的实现,这个实现是在基础层。不采用依赖倒置的传统四层架构,基础层和业务逻辑实现可能会在应用层或领域层,两者逻辑混杂,不利于解耦。
    老师您好
    基础层通过仓储接口过去外部参数,这句话不是很懂,基础层的逻辑,哪些属于基础层逻辑呢?比如根据do的不同状态决定是否存库或者是否发送到消息总线中,是否是指这一类逻辑?还有,是不是领域层(或者是应用层)的对象do和仓储层对象po的转换发生在仓储层,还是仓储层传给基础层的实体就是do而不是po?do还po的转换应该放在哪里?
    根据依赖倒置的原理,感觉基础层暴露给应用层和领域层的仓储层中的接口参数是do(领域实体),而不是po,不知道理解的对不对,望老师解答,感谢感谢感谢
    还有您说的如果采用传统的四层架构,基础层以及基础层业务逻辑实现就会耦合在应用层或领域层,是不是就是上面说的根据不同的状态做不同处理的逻辑,还有没有其他常见的逻辑?感谢老师
    展开

    作者回复: 基础层的逻辑主要是SQL代码,DO和PO的转换和映射以及数据的持久化等。在没有仓储之前,这些代码会跟业务逻辑混杂在一起的。
    领域层和应用层通过仓储接口会将DO的对象传给仓储实现,在仓储实现里面实现DO和PO的转换以及数据的持久化。
    初始化的时候,仓储实现会实现PO到DO的转换,然后返回DO对象。
    这样的话,业务逻辑都是基于DO的操作,不管基础层如何变化,只要DO不发生变化,业务逻辑都不会影响。这样就实现了业务逻辑与基础逻辑的解耦了。

    仓储给你看一段在答疑那一节里面代码。
    有Person聚合根,Person仓储接口和仓储实现。
    /**
     * Person聚合根
     */
    public class Person{
      private String id;
      private String name;
      private int age;
      private boolean gender;
    }

    /**
     * Person仓储接口
     */
    public interface PersonRepositoryInterface {
      void save(Person person);
      void delete(String id);
     }

    /**
     *Person仓储实现
     */
    @Repository
    public class PersonRepositoryImp implements PersonRepositoryInterface {
      private PersonMapper mapper;
      public void save( Person person) {
          mapper.create(person);
      }
      public void delete((String id) {
        mapper.delete(id);
      }
     }
    在应用逻辑中直接用仓储的接口就可以了,数据库相关的逻辑在PersonMapper里面实现。
    PersonRepositoryInterface personRepos;
    personRepos.save(person)

     2
     1
  • 骆驼1089
    2019-11-08
    老师,有一个问题问一下,DDD分层架构,对传入参数校验,应该放在哪层呢?

    作者回复: 应用层。

     3
     1
  • Geek_f0e3c6
    2019-11-07
    前面讲DDD分5层,后面怎么就没了上下文环境层?

    作者回复: 我主要分析的是四层😄。五层只是告诉大家有这个东西。后面也是基于四层来开展的。

    
     1
  • vivi
    2019-11-06
    老师,是对我们所有依赖的基础服务(DB,ES,MQ,REDIS,ZOOKEEPER等)都做成仓储对模式吗?都用一个Repository 接口和对应的实现。

    作者回复: 尽量解耦吧。如果不存在业务逻辑与基础服务耦合的问题,感觉不用也可以。考虑一下综合成本和性价比。

    
     1
  • 八百
    2019-11-05
    仓储用来存储实体,但是实体定义在领域层,仓储在基础层,项目结构里,基础层是访问不到领域层的实体类的吧,是在领域层做一层数据转换吗

    作者回复: DO转PO。

    
     1
  • 。
    2019-10-30
    1.DDD中对于“实体”大部分情况和“数据库表”是一对一的。“实体”采用充血模型,也就是将单表的增删改查功能放在对应的“实体”里。
    2.“聚合根”是将一组有关联的“实体”进行聚集,一次业务操作通过“聚合根”处理多个“实体”,那“聚合根”里的方法(针对这组“实体”的增删改查)就是领域服务。

    欧老师,以上理解是否正确?

    作者回复: 实体除了自身相关的增删改查外,自身相关的其它业务行为也是在实体类内部来实现的,比如实体内不同属性之间的业务逻辑处理,多个同类实体的逻辑处理。
    聚合根内对多个实体操作的方法,主要还是在数据方面的处理,本质上是实体的方法,只不过它是聚合根。
    我理解的领域服务是对多个实体属性以及方法进行组合的业务处理,主要表现为多个实体组合出来的一段复杂业务逻辑。

    
     1
  • Tesla
    2020-02-06
    老师好,现在大多数orm框架都支持多RDBMS,只需要简单配置就能实现mysql到mssql的替换。那还需要依赖倒置吗?

    作者回复: 能做到依赖分离,就不必要了。

    
    
  • Shen
    2020-02-03
    看了几遍,还是不太理解依赖倒置
     1
    
  • 莫离
    2020-02-01
    以前的rpc调用是不是就放到应用服务里面来了,那在这里还叫rpc吗?

    作者回复: 是的,应用层的应用服务会调用其它微服务发布到API网关的服务。

    
    
我们在线,来聊聊吧