DDD领域驱动设计是什么

1 DDD是什么?

DDD是领域驱动设计,是Eric Evans于2003年提出的,离现在有17年。

DDD名为:Domain Driven Design (领域驱动设计) 简称:DDD

2 为什么需要DDD

当软件越来越复杂,实际开发中,大量的业务逻辑堆积在一个巨型类中的例子屡见不鲜,代码的复用性和扩展性无法得到保证。为了解决这样的问题,DDD提出了清晰的分层架构和领域对象的概念,让面向对象的分析和设计进入了一个新的阶段,对企业级软件开发起到了巨大的推动作用。

传统的开发模式MVC:

MVC【 Model-View-Controller(模型-视图-控制器) 模式】,MVVM【Model-View-ViewMode(简称:前后端分离)】,MVCC(并发版本控制)以及后面的SOA架构(面向服务架构,软件接口组件调用)等,而DDD的理解为:将微服务拆分的设计理念改造后嵌入到咱们的代码开发中,只是将服务改造成了领域,不同的领域做着自己相关的业务事情。它能更换的帮助《开发人员》理解:面向对象,系统解耦合,实现高内聚低耦合

ddd设计思想 java demo ddd领域设计思想_领域模型

2.1 POP,OOP,DDD的思维模式

面向过程编程(POP),接触到需求第一步考虑把需求自顶向下分解成一个一个函数。并且在这个过程中考虑分层,模块化等具体的组织方式,从而分解软件的复杂度。当软件的复杂度不是很大,POP也能得到很好的效果。

面向对象编程(OOP),接触到需求第一步考虑把需求分解成一个一个对象,然后每个对象添加一个一个方法和属性,程序通过各种对象之间的调用以及协作,从而实现计算机软件的功能。跟很多工程方法一样,OOP的初衷就是一种处理软件复杂度的设计方法。

领域驱动设计(DDD),接触到需求第一步考虑把需求分解成一个一个问题域,然后再把每个问题域分解成一个一个对象,程序通过各种问题域之间的调用以及协作,从而实现计算机软件的功能。DDD是解决复杂中大型软件的一套行之有效方式,现已成为主流。

2.2 领域设计的优点

DDD最大的好处是:接触到需求第一步就是考虑领域模型,而不是将其切割成数据和行为,然后数据用数据库实现,行为使用服务实现,最后造成需求的首肢分离。DDD让你首先考虑的是业务语言,而不是数据。DDD强调业务抽象和面向对象编程,而不是过程式业务逻辑实现。重点不同导致编程世界观不同。

1.面向对象设计,数据行为绑定,告别贫血模型。

2.优先考虑领域模型,而不是切割数据和行为。

3.业务语义显性化,准确传达业务规则。

4.代码即设计,通过领域设计即可很清晰的实现代码。

5.它通过边界划分将复杂业务领域简单化,帮我们设计出清晰的领域和应用边界,可以很容易地实现业务和技术统一的架构演进。

领域驱动设计,又称"软件核心复杂性应对之道"。是一套基于对象思维的业务建模设计思想,相对于 CRUD 系统有更高的灵活性,是业务人员处理复杂问题的有效手段。

2.3 建立领域模型是最重要的

领域驱动设计告诉我们,在通过软件实现一个业务系统时,建立一个领域模型是非常重要和必要的,因为领域模型具有以下特点:

  1. 领域模型是对具有某个边界的领域的一个抽象,反映了领域内用户业务需求的本质;领域模型是有边界的,只反应了我们在领域内所关注的部分;
  2. 领域模型只反映业务,和任何技术实现无关;领域模型不仅能反映领域中的一些实体概念,如货物,书本,应聘记录,地址,等;还能反映领域中的一些过程概念,如资金转账,等;
  3. 领域模型确保了我们的软件的业务逻辑都在一个模型中,都在一个地方;这样对提高软件的可维护性,业务可理解性以及可重用性方面都有很好的帮助;
  4. 领域模型能够帮助开发人员相对平滑地将领域知识转化为软件构造;
  5. 领域模型贯穿软件分析、设计,以及开发的整个过程;领域专家、设计人员、开发人员通过领域模型进行交流,彼此共享知识与信息;因为大家面向的都是同一个模型,所以可以防止需求走样,可以让软件设计开发人员做出来的软件真正满足需求;
  6. 要建立正确的领域模型并不简单,需要领域专家、设计、开发人员积极沟通共同努力,然后才能使大家对领域的认识不断深入,从而不断细化和完善领域模型;
  7. 为了让领域模型看的见,我们需要用一些方法来表示它;图是表达领域模型最常用的方式,但不是唯一的表达方式,代码或文字描述也能表达领域模型;
  8. 领域模型是整个软件的核心,是软件中最有价值和最具竞争力的部分;设计足够精良且符合业务需求的领域模型能够更快速的响应需求变化;

2.4 通用语言:“一个团队,一种语言”

将模型作为语言的支柱。确保团队在内部的所有交流中,代码中,画图,写东西,特别是讲话的时候都要使用这种语言。例如账号,转账,透支策略,这些都是非常重要的领域概念,如果这些命名都和我们日常讨论以及PRD中的描述保持一致,将会极大提升代码的可读性,减少认知成本。

显性化:就是将隐式的业务逻辑从一推if-else里面抽取出来,用通用语言去命名、去写代码、去扩展,让其变成显示概念,比如"透支策略"这个重要的业务概念,按照事务脚本的写法,其含义完全淹没在代码逻辑中没有突显出来,看代码的人自然也是一脸懵逼,而领域模型里面将其用策略模式抽象出来,不仅提高了代码的可读性,可扩展性也好了很多。

3 领域模型

3.1 贫血模式

贫血模型最早广泛应用源于EJB2,最强盛时期则是由Spring发明,将:

  • “行为”(逻辑、过程);
  • “状态”(数据,对应到语言就是对象成员变量)。

拆散到不同的对象中:

  • 只有状态的对象就是所谓的“贫血对象”(常称为VO——Value Object);
  • 只有行为的对象就是,咱们常见的N层构造中的Logic/Service/Manager
  • MVC就是常见的贫血模型

3.2 充血模式

面向对象设计的实质是:“一个对象是领有状态和行为的”。

比方一个人:

  • 他眼睛什么样鼻子什么样这就是状态;
  • 人能够去打游戏或是写程序,这就是行为。

为什么要有一个“人Manager”这样的货色存在去帮人“打游戏”呢?举个简略的J2EE案例,设计一个与用户(User)相干性能。

传统的设计个别是:

  • 类:User+UserManager;
  • 保留用户调用:userManager.save(User user)。

充血的设计则可能会是:

  • 类:User;
  • 保留用户调用:user.save();
  • User有一个行为是:保留它本人。

4 DDD的分层架构和构成要素

4.1 分层架构

ddd设计思想 java demo ddd领域设计思想_ddd设计思想 java demo_02

整个架构分为四层,其核心就是领域层(Domain),所有的业务逻辑应该在领域层实现,具体描述如下:

用户界面/展现层,负责向用户展现信息以及解释用户命令。

应用层,定义软件要完成的作业并指导富有表现力的领域对象解决问题。 这一层负责执行对业务具有意义的任务或与其他系统的应用层进行交互时需执行的任务。 这一层很“薄”。 它不包含业务规则或知识,仅针对下一层中领域对象之间的协作,协调任务和委派工作。 它不具有反映业务状况的状态,但它可以具有状态,用于反映用户或程序的任务的进度。

领域层,负责表示业务概念、有关业务状况的信息和业务规则。 反映业务状况的状态是通过这个层进行控制和利用的,但有关状态存储的具体技术细节则由基础结构负责实施。 这一层是业务软件的核心。

基础设施层,基础设施层是关于如何将最初存放在域实体中的数据(内存中)持久保存在数据库或另一个持久性存储区中。

4.2 构成要素

实体(Entity,具备唯一ID,能够被持久化,具备业务逻辑,对应现实世界业务对象。

值对象(Value Object,不具有唯一ID,由对象的属性描述,一般为内存中的临时对象,可以用来传递参数或对实体进行补充描述。

领域服务(Domain Service,为上层建筑提供可操作的接口,负责对领域对象进行调度和封装,同时可以对外提供各种形式的服务。

聚合根(Aggregate Root,聚合根属于实体对象,聚合根具有全局唯一ID,而实体只有在聚合内部有唯一的本地ID,值对象没有唯一ID

工厂(Factories,主要用来创建聚合根,目前架构实践中一般采用IOC容器来实现工厂的功能。

仓储(Repository,封装了基础设施来提供查询和持久化聚合操作。
 

CQRS架构

核心思想是将应用程序的查询部分和命令部分完全分离,这两部分可以用完全不同的模型和技术去实现。比如命令部分可以通过领域驱动设计来实现;查询部分可以直接用最快的非面向对象的方式去实现,比如用SQL。这样的思想有很多好处:

  1. 实现命令部分的领域模型不用经常为了领域对象可能会被如何查询而做一些折中处理;
  2. 由于命令和查询是完全分离的,所以这两部分可以用不同的技术架构实现,包括数据库设计都可以分开设计,每一部分可以充分发挥其长处;
  3. 高性能,命令端因为没有返回值,可以像消息队列一样接受命令,放在队列中,慢慢处理;处理完后,可以通过异步的方式通知查询端,这样查询端可以做数据同步的处理;