DDD实战课
欧创新
人保高级架构师
立即订阅
4865 人已学习
课程目录
已完结 23 讲
0/2登录后,你可以任选2讲全文学习。
开篇词 (1讲)
开篇词 | 学好了DDD,你能做什么?
免费
基础篇 (5讲)
01 | 领域驱动设计:微服务设计为什么要选择DDD?
02 | 领域、子域、核心域、通用域和支撑域:傻傻分不清?
03 | 限界上下文:定义领域边界的利器
04 | 实体和值对象:从领域模型的基础单元看系统设计
05 | 聚合和聚合根:怎样设计聚合?
进阶篇 (6讲)
06 | 领域事件:解耦微服务的关键
07 | DDD分层架构:有效降低层与层之间的依赖
08 | 微服务架构模型:几种常见模型的对比和分析
09 | 中台:数字转型后到底应该共享什么?
10 | DDD、中台和微服务:它们是如何协作的?
答疑:有关3个典型问题的讲解
实战篇 (10讲)
11 | DDD实践:如何用DDD重构中台业务模型?
12 | 领域建模:如何用事件风暴构建领域模型?
13 | 代码模型(上):如何使用DDD设计微服务代码模型?
14 | 代码模型(下):如何保证领域模型与代码模型的一致性?
15 | 边界:微服务的各种边界在架构演进中的作用?
16 | 视图:如何实现服务和数据在微服务各层的协作?
17 | 从后端到前端:微服务后,前端如何设计?
18 | 知识点串讲:基于DDD的微服务设计实例
19 | 总结(一):微服务设计和拆分要坚持哪些原则?
20 | 总结(二):分布式架构关键设计10问
结束语 (1讲)
结束语 | 所谓高手,就是跨过坑和大海!
DDD实战课
登录|注册

07 | DDD分层架构:有效降低层与层之间的依赖

欧创新 2019-10-28
你好,我是欧创新。前面我们讲了 DDD 的一些重要概念以及领域模型的设计理念。今天我们来聊聊“DDD 分层架构”。
微服务架构模型有好多种,例如整洁架构、CQRS 和六边形架构等等。每种架构模式虽然提出的时代和背景不同,但其核心理念都是为了设计出“高内聚低耦合”的架构,轻松实现架构演进。而 DDD 分层架构的出现,使架构边界变得越来越清晰,它在微服务架构模型中,占有非常重要的位置。
那 DDD 分层架构到底长什么样?DDD 分层架构如何推动架构演进?我们该怎么转向 DDD 分层架构?这就是我们这一讲重点要解决的问题。

什么是 DDD 分层架构?

DDD 的分层架构在不断发展。最早是传统的四层架构;后来四层架构有了进一步的优化,实现了各层对基础层的解耦;再后来领域层和应用层之间增加了上下文环境(Context)层,五层架构(DCI)就此形成了。
我们看一下上面这张图,在最早的传统四层架构中,基础层是被其它层依赖的,它位于最核心的位置,那按照分层架构的思想,它应该就是核心,但实际上领域层才是软件的核心,所以这种依赖是有问题的。后来我们采用了依赖倒置(Dependency inversion principle,DIP)的设计,优化了传统的四层架构,实现了各层对基础层的解耦。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《DDD实战课》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(55)

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

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

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

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

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

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

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

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

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

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

    2019-10-28
    1
    2
  • 瓜瓜
    作者回复: 依赖倒置后基础层就通过仓储接口获取外部参数了,然后根据这些业务参数完成基础逻辑的实现,这个实现是在基础层。不采用依赖倒置的传统四层架构,基础层和业务逻辑实现可能会在应用层或领域层,两者逻辑混杂,不利于解耦。
    老师您好
    基础层通过仓储接口过去外部参数,这句话不是很懂,基础层的逻辑,哪些属于基础层逻辑呢?比如根据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)

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

    作者回复: 应用层。

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

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

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

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

    2019-11-06
    1
  • 祥敏
    您好,根据三层架构和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相比可能会有前端应用/接口请求方要求的一些个性化的属性或值的映射等。
    第三,简单部分可能会有重叠,但是基于不对外暴露领域层逻辑的目的,会将实体方法封装成领域服务,领域服务再封装为应用服务,然后对外暴露。
    第四,这层本身是公共类,表示部分持久化的功能被提取为公共的面向切面聚合方法来实现
    第五,是这样的。实体值对象的数据逻辑通过聚合根来管理,多实体的业务行为通过领域服务来组合。

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

    作者回复: DO转PO。

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

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

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

    2019-10-30
    1
  • Geek_aa8017
    一般来说,一个领域服务就会对应有一个应用服务吗?

    作者回复: 不一定呢。应用服务可以对多个领域服务组合和编排。

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

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

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

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

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

    2019-12-06
  • OTM
    理解如下,不知是否正确:
    1、用户接口层: Dto 入参、 VO 出参,主要是数据的转发
    2、应用层: 接受Dto 入参,进行Dto 转为DO ; 同时接受领域层返回的DO 进行组装返回VO
    3、领域层: DO 对象,把DO 对象转发为对应PO ,再返回对应DO 对象
    4、基础层: PO 对象进行持久化操作

    作者回复: 你可以看下第16节。里面有详细讲解。

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

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

    2019-11-28
  • Geek_4660f3
    为啥把仓库的接口放在领域层,直接把接口放在基础层,领域层引用感觉没什么区别吧

    作者回复: 区别不大。我主要考虑的是,如果以后微服务之间的聚合需要重新组装的话,直接将代码目录一并复制,就可以将一个聚合打包带走了。

    2019-11-28
    1
  • 王小帅
    貌似对基础层理解有误区,烦请老师帮忙解答下:
    基础层是在每个微服务工程中,而不是以jar包的形式供所有微服务使用?
    如果基础层是在每个微服务工程中,那基础层中的公共的资源不是重复使用了吗?
    如果是以jar包的形式供所有微服务使用,仓储的接口又在各个微服务的领域层,就会出现循环依赖问题吧?

    作者回复: 可能需要区分一下哈。基础层有数据库、API网关等。这类资源是独立于微服务部署的。但是它有驱动或者仓储服务,这部分内容是以jar包的形式跟微服务一起部署的。
    可能还会有以纯jar包形式存在的第三方工具包之类,比如ShardingSphere等。
    基础层的资源类型太多,可能需要分类别具体情况具体分析。

    2019-11-27
  • zj
    领域服务封装多个实体的方法,这多个实体的都是同一个聚合的

    作者回复: 是的。当然,如果要其它聚合实体,可以通过应用服务来做。

    2019-11-27
    1
收起评论
55
返回
顶部