领域驱动设计(Domain Driven Design,DDD)是2004年,由Eric Evans提出的,一个最重要的观点就是:任何软件开发不应该只关注技术,业务领域才是软件开发更应该关注的重点。
领域驱动作为服务设计的顶层视角,业务属性是要强过技术属性的,尤其是为开发某一业务领域而发展的技术模型就是为以后的技术沉淀,比如为了解决金融核心这个业务域的管理问题的中后台系统就沉淀了一套前后端的技术方案。
领域驱动设计中领域的定义:一个领域本质上可以理解为就是一个问题域,只要是同一个领域,那问题域就相同。所以只要我们确定了系统所属的领域,那这个系统的核心业务,即要解决的关键问题、问题的范围边界就基本确定了。领域的本质是问题域,问题域可能根据需要逐层细分,因此领域可分解为子域,子域或可继续分为子子域。。。
在领域驱动设计中根据重要性与功能属性将领域分为三类子域,分别是:核心子域、支撑子域和通用子域。决定产品和企业独特竞争力的子域是核心子域,它是业务成功的主要因素和企业的核心竞争力。没有个性化的诉求,属于通用功能的子域是通用子域,如登陆认证。 还有一种所提供的功能是必须的,但不是通用也不是企业核心竞争力的子域是支撑子域,如单证。
领域驱动设计一般分为两个阶段:
1. 以一种领域专家、设计人员、开发人员都能理解的“通用语言”作为相互交流的工具,在不断交流的过程中发现和挖出一些主要的领域概念,然后将这些概念设计成一个领域模型;
2. 由领域模型驱动软件设计,用代码来表现该领域模型。领域需求的最初细节,在功能层面通过领域专家的讨论得出。
领域驱动设计告诉我们,在通过软件实现一个业务系统时,建立一个领域模型是非常重要和必要的,因为领域模型具有以下特点:
1. 领域模型是对具有某个边界的领域的一个抽象,反映了领域内用户业务需求的本质;领域模型是有边界的,只反应了我们在领域内所关注的部分;
2. 领域模型只反映业务,和任何技术实现无关;领域模型不仅能反映领域中的一些实体概念,如货物,书本,应聘记录,地址,等;还能反映领域中的一些过程概念,如资金转账,等;
3. 领域模型确保了我们的软件的业务逻辑都在一个模型中,都在一个地方;这样对提高软件的可维护性,业务可理解性以及可重用性方面都有很好的帮助;
4. 领域模型能够帮助开发人员相对平滑地将领域知识转化为软件构造;
5. 领域模型贯穿软件分析、设计,以及开发的整个过程;领域专家、设计人员、开发人员通过领域模型进行交流,彼此共享知识与信息;因为大家面向的都是同一个模型,所以可以防止需求走样,可以让软件设计开发人员做出来的软件真正满足需求;
6. 要建立正确的领域模型并不简单,需要领域专家、设计、开发人员积极沟通共同努力,然后才能使大家对领域的认识不断深入,从而不断细化和完善领域模型;
7. 为了让领域模型看的见,我们需要用一些方法来表示它;图是表达领域模型最常用的方式,但不是唯一的表达方式,代码或文字描述也能表达领域模型;
8. 领域模型是整个软件的核心,是软件中最有价值和最具竞争力的部分;设计足够精良且符合业务需求的领域模型能够更快速的响应需求变化;
分而治之的思想,一个复杂的问题域拆分成多个子域问题,子域又包含子子域。
简单朴素的组合方法模式,不同领域的解组合成该问题最终的解。
高内聚低耦合拆分domain域,限界上下文(划分边界),下沉公共逻辑。
抽象领域模型,对于业务能力的表达。
mvc架构与DDD领域分层
mvc三层架构:dao层负责封装数据库模型,把数据库的数据捞出来,service从dao层获取数据处理,并且进行业务操作。
缺点:不利于微服务拆分,代码易冗余,边界混乱。
ddd分层架构:domain层拆分不同的子域(互相隔离),有清晰的限界上下文,有对应的实体model。
优点:利于服务拆分,单一职责,面向服务,提高复用。
DDD四层架构
三层架构对于简单的项目,上手比较简单。但是对于复杂的系统,或者一般项目迭代到了中后期,代码不断增多,将面临难以拆分优化。
DDD分层架构是将一个问题域拆分成多个子域问题,有清晰的上下文边界,通过领域建模的方式表达核心的业务逻辑,分而治之。
通过这种方式,把视角从数据库do的转移到model模型层。
以蚂蚁的sofaboot来看下领域驱动的分层
用户接口层:web服务,controller
test层:单元测试层
core-service层:
- service层:核心服务层,提供公共的服务
- repository层:封装dao层,把do通过convert转换成model领域模型。
domain-service-biz层:领域层,不同的业务子域(高内聚。低耦合)
common层:
- facade层:门面,提供给外部的服务。
- integration层: 集成外部的服务。
- dal层:dao层,封装数据库
- util层:工具类
这里每个模块都有自己的一个上下文,而且是jvm隔离的,通过服务引用的方式去加载别的模块到本地模块的上下文中。
所以这样可以很容易的把一个模块拆成一个微服务剥离出去。
实例:
贴几张图看看,遵循以下设计,单一职责,对修改关闭对扩展开放,依赖倒置。
防腐层:依赖抽象而不依赖具体的子类实现,可以容易修改消息的实现。方便更改业务逻辑,比如熔断、降级等。
仓储层:贫血模型(属性 + get/set)DO ----> 充血模型(属性 + 业务规则)
数据库的orm映射模型DO通过convert转化为业务model模型
参考:实现领域驱动设计 (美)弗农著
https://open.atatech.org/articles/146064
https://www.cnblogs.com/wangsea/p/10282719.html
https://www.sohu.com/a/301582409_355140