DDD领域模型

领域驱动设计(DDD)是一种架构方法论,用于拆解和组织复杂业务。它强调通过识别领域、子域和核心域来确定业务边界,并建立领域模型以支持软件扩展。文章介绍了DDD的关键概念,如子域、通用语言、限界上下文和领域模型的不同类型,以及如何通过事件驱动和领域服务来处理业务逻辑。同时,文章讨论了不同类型的领域模型(失血、贫血和充血模型)及其优缺点,并指出在代码落地时需谨慎处理复杂性。
摘要由CSDN通过智能技术生成

思维导图

  

一 认识领域模型

Domain Driven Design(领域驱动设计, DDD),不是一种架构,而是一种架构方法论,是一种拆解业务、划分业务、确定业务边界的方法,是一种领域设计思想。

DDD(领域驱动设计)实际上是一套软件架构设计的方法论,我们可以在此之上更好的理解业务。并且我们可以根据这套方法论进行架构风格填充,包括微服务架构,面向服务架构,REST风格架构以及六边形架构等等。

解决的问题:软件开发完成后,因需求的变更导致软件不得不增加新的功能,软件越来越冗余,导致最后不得不重构,领域驱动设计能分析好领域相关的业务逻辑,确定好边界,确定同一沟通预言,让软件通过领域模型设计后,更易于扩展。

使用场景和要求:

        1 在一开始就使用领域驱动,已经开发的是不能使用领域驱动的。

        2 要开发的软件非常的复杂,才需要使用到领域驱动

        3 对于项目中架构师的技术要求非常高。并且,架构师不仅仅应该对于各个组件,框架了如指掌。更需要对于业务有非常强的掌控力。、

        4 整个项目中,各个角色都应该非常专业,有相当的专业度。

核心思想:领域驱动的核心思想就是将问题慢慢细化,同时找出最核心的问题点,倾斜资源保证核心资源不出问题,同时也可以通过领域的细分,去慢慢的缩小我们的子域所要解决的问题,并且构建合适的领域模型。

个人理解:我们用软件去解决一些问题,首先要确定软件的边界,确定软件解决的问题,然后围绕这个根本问题(领域),去划分成多个子问题(子领域),分治的方法解决复杂软件的设计问题,划分之后通过一些方法,对子领域进行分析,画出领域模型,基于这种思想,为了达到这种目的,领域驱动设计会有很多其他具体步骤和划分实体等分类,并且有集中领域模型应对不同的情况,牵扯到模式,还有如何开会去讨论领域模型,总之为了解决复杂领域的软件设计,领域驱动不只是空的方法论,里面有很多小的方法来支撑他的各种操作。

二 领域模型关键词解释

领域

领域其实就是我们的范围,而范围实际上就是我们的边界,我们做什么,做到什么程度,最低多少 ,最高多少。

领域其实就是我们的范围,而范围实际上就是我们的边界,我们做什么,做到什么程度,最低多少 ,最高多少。

比如 电商 就是一个领域  ,金融是一个领域,教育是一个领域,你要确定你做的软件产品,具体的领域边界,分析涉及到的数据,业务规则,流程,然后通过面向对象的方式建立一个模型,再选择合适的技术实现。

子域

领域太过于复杂,业务太过于分散,这个时候我们做一个拆分,把领域划分成子域,比如电商系统很复杂,将他拆分成比如一个个的模块,订单,商品,库存,甚至我们的模块还能进行细分,比如库存,可以分为本地库,异地库,三方托管库。划分子域 1 是分治,2是可以对子域进行分析,重要的子域加资源。

核心域(子域)

业务核心,核心的竞争力,因为企业愿景不同,领域愿景也不同,核心域也不同,说白了,就是你们项目最初立项的目的是什么,目标是什么。为什么要做这个项目。核心域的范围并不一定是一次就能确认的,可能需要迭代很多次,每一次都有可能扩大或缩小。

通用域(子域)

整个领域都能够用到的子域,比如我们的认证,权限等等相关的模块,这就是我们的通用域。

支撑域(子域)

支撑域实际上就是不包含核心竞争力的功能,也不包含通用的功能,但是又是必须的支撑。

通用语言

必须要有一个东西能够让我们的团队人员交流起来有一个标准。并且他还需要能够正确的,简单的,清晰的表达业务。让我们的技术专家,业务人员,产品,测试,架构都能够达成共识,并且协同合作。这个叫做通用语言,类似需求文档里的词语解释,就是让大家能在同一维度进行高效的交流沟通。

限界上下文

限界和上下文。限界就是领域的边界,也就是范围,而上下文则是语义环境。通过领域的限界上下文,我们就可以在统一的领域边界内用统一的语言进行交流。

领域模型

领域模型是对领域内的概念类或现实世界中对象的可视化表示,领域模型是用来描述业务对象之间的引用关系。

  • 业务角色,业务角色表示的是一个角色承担的一系列责任。比如收银员,他的责任是计算商品价格,收钱,找零,甚至退换货。
  • 业务实体,业务实体表示的是其实你使用或者可交付的工件,资源,事件。比如电商项目中的商品。你需要给卖家打印的发票。
  • 业务用例,实际上业务用例显示的是协作角色与业务实体之间如何执行工作流程,也就是我们的业务链路

实体(Entity)

正常的实体对象,有唯一键标识,就算所有字段内容一样也不是一个,例如学生,id,姓名,年龄,就算姓名年龄一样,也不是一个。

值对象(Value Object)

没有唯一性标识,例如 学生实体上有一个地址,这个地址是一个对象,里面字段为,省,市,街道,详细地址,这个地址信息对象就是值对象。

聚合聚合根 

平常我们有的实体比较复杂,为了满足业务,有可能会弄出一个非常复杂的实体,里面包含很多实体,跟这个类似,这里的聚合是指同一生命周期,同一业务域的实体聚合成一个聚合根,也就是最外面的实体,并且这个实体管理者里面的所有实体,外面只能通过聚合根进行任何和请求,聚合根再对里面进行操作,这里我感觉就是高内聚,聚合根不易过大。

领域服务

业务逻辑写那个实体中都不合适就写到领域服务中

注意

  • 不能在领域服务里写太多的业务逻辑
  • 不能在领域服务里调用dao和仓储
  • 领域服务视为实体的一种补充,里面的属性和逻辑也和实体一样,不能是基础类型得是含有业务含义的值对象
  • ·领域服务之间可以进行调用,最好是保持父域的领域服务调用子域的领域服务,不允许跨越上下文进行调用

和实体一样,如果有不相关的领域服务的调用,或者有跨上下文的情况,使用领域事件进行解耦

领域事件

事件驱动,有一些代码逻辑,例如下单,后面有很多操作,一般我们一个下单方法里会包含好几个子方法,并且带有if,时间长了会非常冗余,并且方法越来越大,事件驱动就是,当下单之后发一个事件(mq)如果需要做一些操作,多个端接收这个消息事件,然后做自己的操作就行,扩展的话就多一个接收方,对之前代码无侵入修改。

领域专家所关心的发生在领域中的一些事件。
将领域中所发生的活动建模成一系列的离散事件。每个事件都用领域对象来表示...领域事件是领域模型的组成部分,表示领域中所发生的事情。

仓储与工厂

事件风暴

二  领域模型分类

1 失血模型

失血模型实际上就是我们的对象模型中只包含我们的get,set方法,像我们的排序,分页等等任何的通用性操作都不会包含在我们的对象中。

优点

  • 领域对象结构简单

缺点

  • 肿胀的业务服务代码逻辑,难于理解和维护
  • 无法良好的应对复杂业务逻辑和场景

2 贫血模型

贫血模型实际上就是在失血模型的基础上增加了不依赖于持久化的原子领域逻辑。比如我们经常会使用到的排序,分页等等操作。

优点

  • 层次结构清楚,各层之间单向依赖
  • 对于只有少量业务逻辑的应用来说,使用起来非常自然
  • 开发迅速,易于理解

缺点

  • 无法良好的应对非常复杂逻辑和场景

充血模型:

充血模型中实际上我们的领域对象不仅仅包含了我们的非持久化逻辑,甚至还包含了我们的持久化逻辑.那么我们的业务逻辑层在充血模型里还需不需要呢?依然是需要的,但是我们的充血模型的业务层实际上只会做一些整合的操作以及封装事务,其他的操作都会在我们的领域对象中完成

优点

  • 更加符合OO的原则
  • Business Logic层很薄,符合单一职责,不像在贫血模型里面那样包含所有的业务逻辑太过沉重,只充当事务管理以及整合的角色,不和DAO打交道。

缺点

  • 职责不好进行划分,我们的业务逻辑到底是划分到我们的哪一个层级呢?是领域对象还是业务属性呢?哪些划分到领域对象呢?而且持久化的内容都放在我们的领域对象里.所以我们在写业务的时候会深入到领域对象去,这对于开发者的水平要求很高,变相的增加了企业的成本.
  • 其次,由于充血模型包含了太多的操作,你实例化的时候也会有很大的麻烦,拿到了很多你不需要的关联模型.

四 设计与落地

我看了下技术落地的代码,结论就是 非常简单的逻辑会搞得非常复杂,结论就是不建议代码落地。

  • 8
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
领域模型设计在软件开发中扮演着至关重要的角色。特别是在DDD(领域驱动设计)领域中,领域模型是整个软件系统的核心。领域模型不仅仅是一个简单的类或接口的集合,更应该是从业务领域中提炼出的一种业务概念的实现。其主要目的是解决业务领域中的问题,为业务提供更好的支持。 在DDD领域模型设计中,Java代码实例表现得十分出色。在Java中,我们可以通过类、接口、枚举等方式来表示概念,并使用注解、泛型等语言特性更加准确的表示领域模型中的复杂概念和关系。 下面是一个简单的Java代码实例: ```java public class Order implements Entity<Order> { private Long id; private BigDecimal amount; private OrderStatus status; private Customer customer; @Override public boolean sameIdentityAs(Order other) { return other != null && id.equals(other.id); } public void confirm(){ if(status!=OrderStatus.NEW){ throw new IllegalStateException("Only new orders can be confirmed"); } status=OrderStatus.CONFIRMED; } public void cancel(){ if(status==OrderStatus.CANCELLED||status==OrderStatus.DELIVERED){ throw new IllegalStateException("Cancelled or delivered orders cannot be cancelled again"); } status=OrderStatus.CANCELLED; } } ``` 在上述代码中,我们定义了一个订单类Order,该类实现了Entity接口。Order类有一个id属性作为唯一标识,amount属性表示订单金额,status属性表示订单状态。除此之外,Order类还有一个Customer属性,表示订单所属的顾客。 在Order类中,我们还定义了两个方法confirm()和cancel(),分别表示确认订单和取消订单的操作。在这两个方法中,我们使用了状态模式,以保证订单状态的正确性。 此外,我们还实现了Entity接口,并实现了sameIdentityAs()方法,以用于实体对象之间的比较。 以上仅是一个简单的Java代码实例,实际中的领域模型可能更加复杂和抽象。为了设计出更好的领域模型,我们需要充分理解业务领域,进行好的领域分析并利用好Java语言的特性。通过好的领域模型设计可以有效的提高软件系统的可维护性、可扩展性和可重用性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值