浅谈领域驱动设计(DDD:Domain-Driven Design)
来源:《领域驱动设计》是2010年04月人民邮电出版社出版的图书,作者是Eric Evans。本书介绍了面向对象开发人员、系统分析人员合理地组织工作,彼此协作,有条不紊地进行复杂系统的开发,帮助建立丰富而实用的领域模型。
博主也只是刚开始接触这个,理解的也不是很透彻,如有不到位的地方,还请各位海涵!!!
在这里,我是把它当成一种设计思想,或者说是一种设计模式,比较适用于帮助开发人员拓展思维。
心得:分层、领域、领域服务、聚合根、实体、值对象。
模型关系图(Model-Driven Design):
层结构(Layered Architecture):
在这里呢,博主简单用两个图把一般的结构描述了一下,接下来咱们就具体说说每个层级的功能与使用。
1、User Interface
负责向用户展现信息,并且会解析用户行为,也就是常说的展现层。
2、Application Layer
应用层没有任何的业务逻辑代码,它很简单,它主要为程序提供任务处理。
3、Domain Layer
这一层包含有关领域的信息,是业务的核心,领域模型的状态都直接或间接(持久化至数据库)存储在这一层。
4、Infrastructure Layer
为其他层提供底层依赖操作。
层结构的划分是很有必要的,只有清晰的结构,那么最终的领域设计才宜用。不然的话,如果依赖于原有的MVC、MVP等等层级划分的话,这个思想的引用就没有必要了。
实体(Entity) & 值对象(Value Object)
实体
与面向对象中的概念类似,在这里再次提出是因为它是领域模型的基本元素。在领域模型中,实体应该具有唯一的标识符,从设计的一开始就应该考虑实体,决定是否建立一个实体也是十分重要的。
值对象
和我们说的编程中数值类型的变量是不同的,它仅仅是没有唯一标识符的实体,比如有两个收获地址的信息完全一样,那它就是值对象,并不是实体。值对象在领域模型中是可以被共享的,他们应该是“不可变的”(只读的),当有其他地方需要用到值对象时,可以将它的副本作为参数传递。
服务(Services)
当我们在分析某一领域时,一直在尝试如何将信息转化为领域模型,但并非所有的点我们都能用Model
来涵盖。对象应当有属性,状态和行为,但有时领域中有一些行为是无法映射到具体的对象中的,我们也不能强行将其放入在某一个模型对象中,而将其单独作为一个方法又没有地方,此时就需要服务
.
服务具有以下特点:
a)服务中体现的行为一定是不属于任何实体和值对象的,但它属于领域模型的范围内
b)服务的行为一定设计其他多个对象
c)服务的操作是无状态的
模块(Moudles)
对于一个复杂的应用来说,领域模型将会变的越来越大,以至于很难去描述和理解,更别提模型之间的关系了。模块的出现,就是为了组织统一的模型概念来达到减少复杂性的目的的。而另一个原因则是模块可以提高代码质量和可维护性,比如我们常说的高内聚,低耦合
就是要提倡将相关的类内聚在一起实现模块化。
聚合(Aggregates)
聚合被看作是多个模型单元间的组合,它定义了模型的关系和边界。每个聚合都有一个根,根是一个实体,并且是唯一可被外访问的。正是如此,聚合可以保证多个模型单元的不变性,因为其他模型都参考聚合的根。所以要想改变其他对象,只能通过聚合的根去操作。根如果没有了,那么聚合中的其他对象也将不存在。
工厂(Factories)
在大型系统中,实体和聚合通常是很复杂的,这就导致了很难去通过构造器来创建对象。工厂
就决解了这个问题,它把创建对象的细节封装起来,巧妙的实现了依赖反转。当然对聚合也适用(当建立了聚合根时,其他对象可以自动创建)。工厂最早被大家熟知可能还是在设计模式中,的确,在这里提到的工厂也是这个概念。
但是不要盲目的去应用工厂,以下场景不需要工厂:
a)构造器很简单
b)构造对象时不依赖于其他对象的创建
c)用策略模式就可以解决
仓库(Repository)
仓库
封装了获取对象的逻辑,领域对象无须和底层数据库交互,它只需要从仓库中获取对象即可。仓库可以存储对象的引用,当一个对象被创建后,它可能会被存储到仓库中,那么下次就可以从仓库取。如果用户请求的数据没在仓库中,则会从数据库里取,这就减少了底层交互的次数。
举个例子:
在这里呢,服务(service)的作用是处理业务逻辑。仓库(Repository)的作用是对数据增删查改的操作。工厂(Factory)的作用是获取数据,与数据表字段相对应,基本没有别的操作。实体(Entity)的作用是存数据,与工厂相呼应。
这个是博主在使用领域驱动设计思想时写的项目,运用的是laravel框架,主要的流程是:
路由(Route)->控制器(Controller)->接口(Api)->服务(Service)->仓库(Repository)->工厂(Factory)->实体(Entity)
虽然在刚开始的时候,博主跟你们一样觉得这样写反而把事情复杂化了似的,但是经过一段时间的磨合,会发现使用分层结构来写的话,代码修改起来真的很方便。在这里我们只是把原来的代码给分化了,每一部分都有它们专属的位置,这样的话在重构的时候我们可能只需要把我们需要的那一部分做一个修改就可以了,完全不必像之前那样去慢慢追代码,打断点。
前期开发的时候会消耗一些时间,但是后面就会越来越轻松,这么好的设计方式你要不要也来试试???
由于博主不太擅长使用官方术语形容专业名词,在前期对名词简介时部分摘自Pursue的文章:https://www.jianshu.com/p/b6ec06d6b594