MVC有什么问题?什么是领域驱动设计?能解决什么?

2022-08-1122:51:17软件工程与架构Comments1,115 views字数 2867阅读模式

传统的MVC会有什么问题

MVC有什么问题?什么是领域驱动设计?能解决什么?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

mvc结构文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

mvc结构的特点文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

  1. 对象只是数据的载体,它没有相关行为,可以理解为是对数据移动、处理和实现的过程,这种对象我们称之为贫血领域对象。
  2. 业务初期,我们的功能大都非常简单,普通的CRUD就能满足,此时系统是清晰的。随着迭代的不断演化,业务逻辑变得越来越复杂,我们的系统也越来越复杂。

mvc结构暴露的问题文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

  1. 所有的业务逻辑几乎集中在service层,包括什么缓存、mq、第三方的系统调用的操作,这会导致service层非常的臃肿,上下两层非常的薄,不同service之间的边界非常不清晰。
  2. 对一个model的操作(比如状态)可能会散落到很多个service中,原本的代码意图会渐渐不明确,我们将这种情况称为由贫血症引起的失忆症
  3. 所有依赖的外部组件都耦合到了service层,如果需要升级需要对service层进行大量改动,那么改动可能会影响业务的核心逻辑。

这和我们软件开发所追求的高内聚、低耦合、可维护性似乎点背道而驰。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html


领域驱动设计能解决的问题

30年以前,国外的软件设计人员就已经意识到领域建模和设计的重要性,并形成一种思潮,Eric Evans(国外大牛)将其定义为领域驱动设计(Domain-Driven Design,简称DDD)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

DDD它是一个方法论,它指导软件开发人员怎样去划分领域(业务逻辑边界),领域之间的交互方法及依赖关系,定义了领域之中的元素类型以及领域驱动设计中的代码结构等等。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

在这个方法论的指导下使得我们软件系统朝高内聚、低耦合、可维护性高的方向发展。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html


领域驱动设计几个重要的概念

先理解名词的含义,注意看加粗的字体,这对领域的设计很重要。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

领域文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

现实世界中,领域包含了问题域和解决系统。一般认为软件是对现实世界的部分模拟。在DDD中,解系统可以映射为一个个限界上下文,限界上下文就是软件对于问题域的一个特定的、有限的解决方案。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

限界上下文文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

一个由显示边界限定的特定职责。领域模型便存在于这个边界之内。在边界内,每一个模型概念,包括它的属性和操作,都具有特殊的含义。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

领域服务文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

一些重要的领域行为或操作,可以归类为领域服务。它既不是实体,也不是指对象的范畴。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

实体文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

当一个对象由其标识(而不是属性)区分时,这种对象称为实体(Entity)。mvc中的model其实是对实体的抽象,比如人(person)是一个抽象概念,黑人、白人是对抽象的进一步的实现。最简单的,公安系统的身份信息录入,对于人的模拟,即认为是实体,因为每个人是独一无二的,且其具有唯一标识(如公安系统分发的身份证号码)。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

值对象文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

当一个对象用于对实体属性进行描述而没有唯一标识时,它被称作值对象(Value Object)。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

例:比如颜色信息,我们只需要知道{“name”:“黑色”,”css”:“#000000”}这样的颜色信息就能够满足要求了,这避免了我们对标识追踪带来的系统复杂性。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

聚合根文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

Aggregate(聚合)是一组相关实体的集合,作为一个整体被外界访问,聚合根(Aggregate Root)是这个聚合的根节点。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

Repository(仓库)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

可以理解为实体的仓库,可以从数据库中拿出实体,也可以从缓存中拿出实体,这个概念的好处是,如果我的存储换了,我的缓存换了,只需要改变这一层即可,其他的业务逻辑几乎不用改动,这一层主要是操作数据库或者缓存。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

防腐层文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

外部变化我们控制不了,但是内部变化是可控的,因为对于内部来说,我需要什么我自己是最清楚的。所以这一层的作用主要是用来对接外部系统,当外部系统发生变化的时候我只需要调整防腐层就好,内部的业务逻辑几乎不需要调整。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

MVC有什么问题?什么是领域驱动设计?能解决什么?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

名词关系文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

说明:聚合根中包含实体和值对象,值对象也可以包含值对象,领域服务可以调用聚合根中的行为方法。也可以通过防腐层调用外部服务,多个领域服务组成限界上下文,多个限界上下文组成领域。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html


领域驱动设计的结构

MVC有什么问题?什么是领域驱动设计?能解决什么?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

DDD结构文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

  • service-领域服务层
  • repository-仓库层
  • Aggregate Root-聚合根层
  • entity-实体层
  • value object-值对象层
  • ACL-防腐层

service层可以理解为业务逻辑编排层,service层调用repository层获取聚合根对象,然后执行聚合根和实体相关的行为方法。也可以调用防腐层处理外部数据。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

防腐层贯彻整个context,业务逻辑大部分封装到聚合根层和实体层,达到了逻辑内聚,实体行为复用的目的,多个上下文构成一个应用。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

MVC有什么问题?什么是领域驱动设计?能解决什么?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

数据流转文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html


领域驱动设计实践

举例文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

用户可以使用手机号码或者邮箱登录我们的系统,如果登录成功之后判断用户30天内是否是第一次登录,如果是就给用户发送一条短信,提示用户”欢迎回来“。(PM:怎么实现我不管,反正今天上线!)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html


分析文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

MVC有什么问题?什么是领域驱动设计?能解决什么?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html


mvc实现代码结构文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

使用golang实现,java实现有需要的私聊我。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

MVC有什么问题?什么是领域驱动设计?能解决什么?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

mvc结构实现文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

核心逻辑文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

controller层代码文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

比较简单,就不贴了。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html


model层代码文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

MVC有什么问题?什么是领域驱动设计?能解决什么?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

user.go文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html


service层代码文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

MVC有什么问题?什么是领域驱动设计?能解决什么?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

user_service.go文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html


问题一:对外部的依赖耦合严重文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

什么是外部的依赖?不属于当前域内的设施和服务都可以当成是外部依赖,比如数据库,数据库schema,RPC,消息中间件,缓存,ORM框架,他们都有一个特征,都是可替换的,比如一个数据库可以从mysql缓存oracle,缓存可以从redis换成memcache等等,这些都是属于业务域核心逻辑之外的东西,你对他们是没有控制权,所以你要做的事,即使这些外部依赖发生了变化,也能将自己的修改控制在最小范围,这就是系统的可维护性。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

  • 在service中直接调用了日志的RPC服务,如果后期日志服务升级,可能会影响登录逻辑。
  • 在service中使用gorm框架直接从数据库查询用户,如果后期流量比较大,使用了缓存,需要先查询缓存,改动可能会影响登录的核心逻辑。

问题二:业务逻辑耦合严重文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

  • 注册逻辑中耦合了参数校验,手机号码校验逻辑,如果后续需要新增检验逻辑势必会对核心逻辑进行修改。
  • 注册逻辑中耦合了查询用户最后一次登录时间的逻辑,理论上这应该属于用户的行为。

DDD实现代码结构文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

MVC有什么问题?什么是领域驱动设计?能解决什么?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

DDD代码结构文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

  1. acl-防腐层,主要逻辑调用日志服务获取用户最后一次登录时间,发送短信逻辑。
  2. entity-实体、聚合根层,这两个我习惯放一起,因为聚合根就是聚合了实体和值对象的一种特殊实体。
  3. repository-仓库层,主要对应了数据库的操作以及数据库的schema,缓存操作等。
  4. service-业务逻辑编排层。
  5. valobj-值对象层

acl层代码文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

MVC有什么问题?什么是领域驱动设计?能解决什么?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

user_log_acl.go文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

MVC有什么问题?什么是领域驱动设计?能解决什么?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

sms_acl.go文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html


entity层代码文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

MVC有什么问题?什么是领域驱动设计?能解决什么?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

user.go文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html


repository层代码文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

MVC有什么问题?什么是领域驱动设计?能解决什么?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

user.go文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html


service层代码文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

MVC有什么问题?什么是领域驱动设计?能解决什么?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

service.go文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html


valobj层代码文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

MVC有什么问题?什么是领域驱动设计?能解决什么?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

username.go文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html


这样做的好处文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html

  1. 代码结构及业务逻辑清晰。。
  2. 所有用户域的逻辑全部内聚在User聚合根对象,方便复用及维护,单测起来非常方便。
  3. 防腐层的使用,不管外部怎么调整,都不会影响我登录的核心逻辑。
  4. 仓库的使用,后续orm框架的升级替换等等,都不会影响我登录的核心逻辑。
  5. 系统的扩展性,可维护下显著提升。
文章源自菜鸟学院-https://www.cainiaoxueyuan.com/arc/26980.html
  • 本站内容整理自互联网,仅提供信息存储空间服务,以方便学习之用。如对文章、图片、字体等版权有疑问,请在下方留言,管理员看到后,将第一时间进行处理。
  • 转载请务必保留本文链接:https://www.cainiaoxueyuan.com/arc/26980.html

Comment

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定