原文链接: https://dev.to/salah856/implementing-domain-driven-design-part-i-5a72

简单的代码!

踢足球很简单,难的是踢简单的足球。— 克鲁伊夫

如果我们将这句话用到编程上,我们可以说;

写代码很简单,难的是写简单的代码。

什么是领域驱动设计?

领域驱动设计(DDD)是一种软件开发方法,通过将实现结合不断发展的模型来满足复杂的需求。

DDD适用于复杂的领域和大规模的应用程序,而不是简单的CRUD应用程序。

它专注于核心领域逻辑,而不是基础设施细节。它有助于构建灵活、模块化和可维护的代码库。

OOP & SOLID

DDD的实现高度依赖于面向对象编程(OOP)和SOLID原则。

实际上,它实现并扩展了这些原则。因此,对OOP和SOLID的良好理解对你实现DDD有很大帮助。

DDD分层和整洁架构

基于领域驱动的解决方案有四个基本分层。

业务逻辑分为两层,领域层和应用层,它们包含不同类型的业务逻辑;

  • 领域层实现领域/系统的核心、独立于用例的业务逻辑。

  • 应用层基于领域实现应用的用例。可以将用例视为用户界面 (UI) 上的用户交互。

  • 表示层包含应用程序的UI元素(页面、组件)。

  • 基础设施层通过实现对第三方库和系统的抽象和集成来支持其他层。

相同的分层可以如下图所示,称为整洁架构,有时也称为洋葱架构:

核心构建块

DDD主要关注领域层和应用层,而忽略了表示层和基础设施。它们被视为细节,业务层不应依赖它们。

这并不意味着表示层和基础设施层不重要。

它们非常重要。UI框架和数据库提供商有自己的规则和最佳实践,你需要了解和应用它们。但是,这些不在DDD的主题中。

本节介绍领域层和应用层的基本构建块。

领域层构建块

  • 实体Entity:实体是具有自己的属性(状态、数据)和实现在这些属性上执行的业务逻辑的方法的对象。实体由其唯一标识符 (Id) 表示。具有不同Id的两个实体对象被视为不同的实体。

  • 值对象Value Object:值对象是另一种领域对象,由其属性而不是唯一的Id进行标识。这意味着具有相同属性的两个值对象被视为同一个对象。值对象通常被实现为不可变的,并且大多比实体简单得多。

  • 聚合Aggregate和聚合根Aggregate Root:聚合是由聚合根对象绑定在一起的一组对象(实体和值对象)。聚合根是具有一些额外职责的特定类型的实体。

  • 仓储Repository(接口):仓储是一个类似于接口的集合,领域和应用层使用它来访问数据持久性系统(数据库)。它对业务代码隐藏了DBMS的复杂性。领域层包含存储库的接口。

  • 领域服务Domain Service:领域服务是实现领域核心业务规则的无状态服务。它是对于实现依赖于多个聚合(实体)类型或一些外部服务的领域逻辑很有用。

  • 规范Specification:规范用于为实体和其他业务对象定义命名的、可重用的和可组合的过滤器。

  • 领域事件Domain Event:领域事件是一种在发生领域特定事件时以松散耦合的方式通知其他服务的方式。

应用层构建块

  • 应用服务Application Service:应用服务是无状态的实现应用用例的服务。应用服务通常会获取并返回DTO。它由表示层使用。它使用和协调领域对象来实现用例。用例通常被视为一个工作单元。

  • 数据传输对象(DTO):DTO是一个没有任何业务逻辑的简单对象,用于在应用层和表示层之间传输状态(数据)。

  • 工作单元(UOW):工作单元是应作为事务单元完成的原子工作。UOW中的所有操作都应该在成功时提交或在失败时回滚。

实现: 整体结构

.NET解决方案

下图显示了使用ABP的应用程序启动模板创建的Visual Studio解决方案:

领域层

领域层分为两个项目;

  • IssueTracking.Domain,是基本的领域层,包含之前介绍的所有构建块(实体、值对象、领域服务、规范、仓储库接口等)。

  • IssueTracking.Domain.Shared,是一个精简项目,其中包含一些属于领域层但与所有其他层共享的类型。例如,它可能包含一些与领域对象相关的常量和枚举,但需要被其他层重用。

应用层

应用层也分为两个项目;

  • IssueTracking.Application.Contracts,包含应用服务接口和这些接口使用的DTO。该项目可以由客户端应用程序(包括 UI)共享。

  • IssueTracking.Application,是实现Contracts项目中定义的接口的基本应用层。

表示层

  • IssueTracking.Web,是此示例的ASP.NET Core MVC/Razor Pages应用程序。这是为应用程序和API提供服务的唯一可执行应用程序。

远程服务层

  • IssueTracking.HttpApi,包含解决方案定义的HTTP API。它通常包含MVC控制器和相关模型(如果可用)。因此,在此项目中编写HTTP API。

  • IssueTracking.HttpApi.Client,一个需要使用你的HTTP API的C#应用程序。一旦客户端应用程序引用了这个项目,它就可以直接注入和使用应用程序服务。这可以在ABP框架的动态C#客户端API代理系统的帮助下实现。

基础设施层

在DDD实现中,你可能有一个基础设施项目来实现所有的抽象和集成,或者可能对每个依赖项都有不同的项目。

我们建议采取平衡的方法;为主要基础设施依赖项(如 Entity Framework Core)创建单独的项目,为其他基础设施创建一个通用基础设施项目。

ABP的启动解决方案有两个用于Entity Framework Core集成的项目;

  • IssueTracking.EntityFrameworkCore,是EF Core必不可少的集成包。应用程序的DbContext、数据库映射、存储库的实现以及其他与EF Core相关的内容都位于此处。

  • IssueTracking.EntityFrameworkCore.DbMigrations,是一个用于管理Code First数据库迁移的特殊项目。这个项目中有一个单独的DbContext来跟踪迁移。除了需要创建新的数据库迁移或添加具有一些数据库表并且需要创建新的数据库迁移的应用程序模块外,通常不会过多地接触这个项目。

还有一个项目,IssueTracking.DbMigrator,它是一个简单的控制台应用程序,它迁移数据库模式并在执行它时初始种子数据。

它是一个有用的实用程序,你可以在开发和生产环境中使用它。

解决方案中项目的依赖关系

基于DDD的应用程序执行流程

下图显示了基于DDD模式开发的Web应用程序的典型请求流。

  • 请求通常从用户界面(一个用例)上的用户交互开始,该交互导致对服务器的HTTP请求。

  • 表示层(或分布式服务层)中的MVC控制器或Razor页面处理程序处理请求,并可以在此阶段执行一些横切关注点(授权、验证、异常处理等)。控制器/页面注入相关的应用程序服务接口并通过发送和接收DTO调用其方法。

  • 应用服务使用领域对象(实体、存储库接口、领域服务等)来实现用例。应用层实现了一些横切关注点(授权、验证等)。应用程序服务方法应该是一个工作单元。这意味着它应该是原子的。

大多数横切关注点都是由ABP框架自动且按惯例实现的,你通常不需要为它们编写代码。

数据库提供者/ORM 独立性

领域层和应用层应该与ORM/数据库提供者无关。

它们应该只依赖于Repository接口,并且Repository接口不使用任何ORM特定对象。

使用这个原则的主要原因如下;

  1. 使你的领域/应用程序基础架构独立,因为基础架构将来可能会发生变化,或者你以后可能需要支持第二种数据库类型。

  2. 使你的领域/应用程序专注于业务。通过隐藏仓储后面的基础设施细节来编写代码。

  3. 为了使你的自动化测试更容易,因为你可以在这种情况下模拟存储库。

如果你觉得这篇文章对你有所启发,请关注我的个人公众号”My IO“

实现DDD领域驱动设计: Part 1相关推荐

  1. DDD领域驱动设计之聚合、实体、值对象

    关于具体需求,请看前面的博文:DDD领域驱动设计实践篇之如何提取模型,下面是具体的实体.聚合.值对象的代码,不想多说什么是实体.聚合等概念,相信理论的东西大家已经知晓了.本人对DDD表示好奇,没有在真 ...

  2. DDD领域驱动设计 — 贫血模型与充血模型

    文章转载来源:https://juejin.cn/post/6917125801460629518 | 前言  要想深入掌握和了解 DDD 领域驱动设计的核心,那无论如何也绕不开两大较为抽象的概念-- ...

  3. DDD 领域驱动设计:贫血模型、充血模型的深入解读!

    作者:JavaEdge在掘金 链接:https://juejin.cn/post/6917125801460629518 -     前言     - 要想深入掌握和了解 DDD 领域驱动设计的核心, ...

  4. 浅谈我对DDD领域驱动设计的理解

    从遇到问题开始 当人们要做一个软件系统时,一般总是因为遇到了什么问题,然后希望通过一个软件系统来解决. 比如,我是一家企业,然后我觉得我现在线下销售自己的产品还不够,我希望能够在线上也能销售自己的产品 ...

  5. C#进阶系列——DDD领域驱动设计初探(五):AutoMapper使用

    前言:前篇搭建了下WCF的代码,就提到了DTO的概念,对于为什么要有这么一个DTO的对象,上章可能对于这点不太详尽,在此不厌其烦再来提提它的作用: 从安全上面考虑,领域Model都带有领域业务,让Cl ...

  6. DDD 领域驱动设计:贫血模型、充血模型的深入解读

    点击上方"朱小厮的博客",选择"设为星标" 后台回复"书",获取 后台回复"k8s",可领取k8s资料 -     前言 ...

  7. [转]浅析DDD(领域驱动设计)

    最近在做一些微服务相关的设计,内容包括服务的划分,Restful API的设计等.其中比较棘手的就是Service的职责划分:如何抽象具有统一业务范畴的Model,使其模块化,又如何高度提炼并组合多模 ...

  8. 浅析DDD(领域驱动设计)

    最近在做一些微服务相关的设计,内容包括服务的划分,Restful API的设计等.其中比较棘手的就是Service的职责划分:如何抽象具有统一业务范畴的Model,使其模块化,又如何高度提炼并组合多模 ...

  9. DDD 领域驱动设计落地实践:六步拆解 DDD

    引言 相信通过前面几篇文章的介绍,大家对于 DDD 的相关理论以及实践的套路有了一定的理解,但是理解 DDD 理论和实践手段是一回事,能不能把这些理论知识实际应用到我们实际工作中又是另外一回事,因此本 ...

  10. DDD 领域驱动设计-三个问题思考实体和值对象(续)

    上一篇:DDD 领域驱动设计-三个问题思考实体和值对象 说实话,整理现在这一篇博文的想法,在上一篇发布出来的时候就有了,但到现在才动起笔来,而且写之前又反复读了上一篇博文的内容及评论,然后去收集资料, ...

最新文章

  1. head first python菜鸟学习笔记(第六章)
  2. “AI独角兽”半年巨亏52亿 旷视科技的IPO之路会好走吗?
  3. android主板接口定义,范例解析:学习Android的IPC主板模式
  4. Windows用户安全小技巧
  5. Dapper操作MySQL数据库获取JSON数据中文乱码
  6. 法学学士学位的完整形式是什么?
  7. MobileNet论文笔记
  8. ubuntu下面如何切换virtual_box的鼠标
  9. linux下的文件结构
  10. 关于java.lang.reflect.InvocationTargetException。
  11. JavaScript--如何插入JS
  12. [2018.08.08 T1] 签到题
  13. hashmap containsvalue时间复杂度_面试宝典:数据结构-HashMap
  14. 数据库系统原理课程设计
  15. 以太网和令牌环网的区别
  16. 实现B站弹幕很难么?这个开源项目了解一下
  17. veeam备份oracle数据库,实战veeam BR 10备份Oracle RAC 19c PDB容器数据库
  18. QQ等级图标对应的算法
  19. 如何关闭任务栏中chrome浏览器的通知图标
  20. 这样的萌妹,谁不爱呢?

热门文章

  1. CentOS Linux 系统命令之rmdir命令
  2. Extjs 中的cookie设置
  3. 如何识别是三层交换机还是二层交换机
  4. win7 32位 安装opencv-python后,运行时提示 from .cv2 import *: DLL load failed: 找不到指定的模块 的解决办法...
  5. 异常处理、socke基于TCP协议编程
  6. android 打开系统相机,
  7. 桥接模式下的手机-电脑-开发板连接
  8. [9月29日的脚本] 枚举SharePoint列表(PowerShell)
  9. 宝宝的成长脚印6/15
  10. 开源播放器 Banshee 发布 1.0 beta 2