基于ABP落地领域驱动设计-01.全景图

什么是领域驱动?

领域驱动设计(简称:DDD)是一种针对复杂需求的软件开发方法。将软件实现与不断发展的模型联系起来,专注于核心领域逻辑,而不是基础设施细节。DDD适用于复杂领域大规模应用,而不是简单的CRUD应用。它有助于建立一个灵活、模块化和可维护的代码库。

OOP 和 SOLID

DDD实现高度依赖面向对象编程思想(OOP)SOLID原则。实际上,它实现并扩展了这些原则。因此,在真正实施DDD时,对OOP和SOLID的良好理解将对您有很大帮助。

DDD 和 Clean Architecture

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

业务逻辑分布在两个层中:领域层(Domain Layer)和 应用层(Application Layer),分别包含不同类型的业务逻辑:

•领域层:实现领域(或系统)中的用例独立的核心业务逻辑。•应用层:基于领域的应用程序用例,应用程序用例可以看作是用户界面上的用户交互。•展示层:包含应用程序UI元素(页面、组件等)。•基础层:支持层,通过对第三方类库的调用或系统的抽象和集成来实现对其他层的支持。

简洁架构(Clean Architecture) 是与之相同的分层架构,又称为洋葱架构(Onion Architecture)。

从架构图可以看出,每一层只直接依赖于它内部的层,最独立的层是领域层,显示在最内圈中。

核心构件

DDD主要关注领域层和应用层,展示层和基础层被看作是细节,业务层不应该依赖于它们,但这并不意味着展示层和基础层不重要,它们也非常重要。展示层中的UI框架和基础层中的数据提供程序有他们自己的实现规则和最佳实践,需要了解和应用。然而,这些并不在DDD的主题中,我们重点来看领域层和应用层的基本构件。

领域层构件

实体(Entity):一个实体是一个对象,该对象包含自己的属性和方法,属性用于存储数据和描述状态;方法结合属性实现业务逻辑。一个实体使用唯一标识(ID)来表示,两个实体对象ID不同则是为不同的实体。•值对象(Value Object):值对象是另一种类型的领域对象,该对象由其属性而不是唯一ID来标识。意思是说,只有全部属性相同才会被认为是同一个对象。值对象通常被实现为不可变的,而且大多比实体简单得多。•聚合和聚合根:聚合根是一个特定类型的实体,具有额外的职责。聚合是以聚合根为中心绑定在一起的一组对象,对象包括实体和值对象。•仓储(接口):仓储是一个类似集合的接口,被领域层和应用层用来访问数据持久化系统(数据库)。它将数据库的复杂性从业务代码中隐藏起来。领域层包含仓储接口。•领域服务:领域服务是无状态服务,实现核心领域业务规则。用于实现依赖于多个聚合(实体)或外部服务的领域逻辑。•规约:用于为实体和其他业务对象定义可命名的、可重用的和可组合的过滤器。•领域事件:领域事件是一种低耦合的通知方式,当一个特定的领域事件发生时,会通知其他服务。

应用层构件

应用服务:应用服务是无状态服务,实现应用程序用例。一个应用服务通常获取和返回数据传输对象(DTOs),用于展示层。调用领域对象来实现用例。一个用例通常被认为是一个工作单元。•数据传输对象(DTO):DTO是简单对象,不包含任何业务逻辑,只用于在应用层和展示层传递数据。•工作单元:一个工作单元是一个原子工作。在工作单元中的所有操作统一提交,要么全部成功,失败则全部回滚。

项目分层

下面图片是在 .Net解决方案(Visual Studio),基于 ABP 应用程序启动模板创建的解决方案结构:

解决方案名称为:IssueTracking 。解决方案的项目分层考虑到DDD原则,同时兼顾开发和部署实践而划分。

示例项目业务场景参考 GitHub 问题追踪,这个场景比较通用,使用过Git的开发人员都了解。

领域层

领域层拆分为两个项目:

•IssueTracking.Domain:领域层,该项目包含所有领域层构件,比如:实体、值对象、领域服务、规约、仓储接口等。•IssueTracking.Domain.Shared:领域共享层,包含属于领域层,但是与其他层共享的类型。举个例子:定义的常量和枚举,既在领域对象中使用,也要在其他层中使用,放在该项目中。

应用层

应用层拆分为两个项目:

•IssueTracking.Application.Contracts:应用契约层,包含应用服务接口和数据传输对象(用于接口),该项目被应用程序客户端引用,比如:WEB项目、API客户端项目。•IssueTracking.Application:应用层,实现在 Contracts 项目中定义的接口。

展示层

•IssueTracking.Web:可执行程序,调用应用服务或APIs,当前解决方案中是 ASP.NET Core MVC/Razor Pages 应用。

ABP框架提供不同类型的UI框架,比如:Angular和Blazor。如果采用这种UI框架,解决方案为前后端分离架构,解决方案中不包含 IssueTracking.Web 项目,而是通过 IssueTracking.HttpApi.Host 项目作为一个独立的端点提供 HTTP API 服务,供客户端调用。

远程服务层

•IssueTracking.HttpApi:远程服务层,该项目用于定义 HTTP APIs,通常包含 MVC Controller 及相关的模型。

大多数时候,API Controller 只是应用服务的包装器,以便将它们公开给远程客户端。因为ABP框架提供根据应用服务接口自动生成API Controller,实现自动配置并将你的应用服务公开为API控制器,所以通常不会在这个项目中创建控制器。

•IssueTracking.HttpApi.Client:远程服务代理层,客户端应用程序引用该项目,将直接通过依赖注入使用远程应用服务,该项目基于ABP Framework动态C#客户端API代理系统实现。在C#项目中需要调用HTTP APIs时,会非常有用。

在解决方案的 test 文件夹中有一个控制台应用程序,名为IssueTracking.HttpApi.Client.ConsoleTestApp。它只是使用IssueTracking.HttpApi.Client项目来消费应用程序所暴露的API。它只是一个演示应用程序,可以安全地删除它。如果认为不需要,甚至可以删除IssueTracking.HttpApi.Client项目。

基础层

实现DDD时,可以使用一个基础层项目来实现所有的集成和抽象,当然也可以为不同依赖创建不同项目。

建议折中处理,为核心基础依赖创建单独项目,比如:Entity Framework Core;另外创建一个公共基础项目存放其他基础设施。

启动模板中包含两个项目对 Entity Framework Core 进行集成:

•IssueTracking.EntityFrameworkCore:EF Core核心基础依赖项目,包含:数据上下文、数据库映射、EF Core仓储实现等。•IssueTracking.EntityFrameworkCore.DbMigrations:数据迁移项目,是一个特殊的工具项目,用于管理 Code First 数据迁移。项目中有独立的数据上下文,用于数据迁移。除了在需要创建新的数据库迁移或添加应用程序模块增加相应的表时,需要创建一个新的数据库迁移之外,通常不会涉及这个项目。

可能你会疑惑为什么集成EF Core创建了两个项目,因为模块化的需要。每一个模块有其独立的 DbContext,应用程序也有一个 DbContextDbMigration项目包含用于跟踪和应用单个迁移模块的联合。虽然大多数时候您不需要了解它,但您可以查看 EF Core迁移文档,以获得更多信息。

其他项目

还有一个项目,IssueTracking.DbMigrator,一个简单的控制台应用程序,当你执行它时,会迁移数据库结构并初始化种子数据。这是一个有用的实用程序,可以在开发和生产环境中使用它。

项目依赖关系

下图是解决方案中项目引用(依赖)关系

前面我们讲解了各个项目的作用,接下来梳理项目之前的关系:

Domain.Shared 其他项目直接或间接引用,项目中定义的类型在所有项目中共享。•Domain 只引用 Domain.Shared,比如:在 Domain.Shared 中定义的 IssuType 枚举类型需要在 Domain 项目中 Issue 实体中用到。•Application.Contracts 依赖 Domain.Shared,这样我们可以在 DTOs 中使用这些共享类型。比如:CreateIssueDto中可以直接使用 IssueType 枚举。•Application 依赖 Application.Contracts ,因为 Application 实现 Application.Contracts 中定义的服务接口和使用 DTO 对象。同时,引用 Domain 项目,在应用服务中使用仓储接口领域对象。•EntiryFrameworkCore 依赖 Domain ,映射 Domain 对象(实体和值类型)到数据库表(ORM)并实现在 Domain 中定义的仓储接口。•HttpApi 依赖 Application.Contract,在控制器在内部对 应用服务接口 进行依赖注入。•HttpApi.Client 依赖 Application.Contract 消费应用服务•Web 依赖 HttpApi ,发布里面定义的HTTP APIs。另外,通过这种方式,它间接地依赖于 Application.Contracts 项目,可以在页面/组件中使用应用服务。

虚拟依赖

当你仔细查看解决方案依赖关系图时,会看到还有两个依赖关系,在上图中用虚线表示。Web项目依赖于 Application 和 EntityFrameworkCore 项目,理论上不应该是这样,但实际上是这样。

这是因为 Web 是运行和托管应用程序的最终项目,应用程序在运行时需要应用服务和仓储的实现

这个设计决定有可能让你在展示层中使用实体EF Core 对象,但这应该是严格避免的。然而,我们发现替代设计过于复杂。在这里,如果你想消除这种依赖性,有两个备选方案:

•将 Web 项目转换为 Razor类库类型,然后创建新项目,比如:Web.Host,引用 Web 项目、Application 和 EntityFrameworkCore 项目。在新项目中,不需要编写任何UI代码,只用来做承载项目。•从 Web 项目中移除 Application 和 EntityFrameworkCore 项目引用,作为 ABP 插件模块在应用初始化时加载程序集。

DDD应用程序的执行流程

下图显示基于DDD模式开发的Web应用请求的基本流程:

•通过UI用户交互(可以看做是一个用例)发起HTTP请求到服务器

•在展示层 MVC Controller(HTTP API) 或 Razor Page Handler(Razor Pages)接收并处理请求,在此阶段执行横切关注点,如:授权、输入验证、异常处理、审计日志、缓存等。Controller或Page在构造函数中注入应用服务接口,调用方法发送和接收DTO对象。•应用服务使用领域对象(实体、仓储接口、领域服务等)实现用例。在此阶段,应用层执行横切关注点,如:授权、验证、审计日志、工作单元等。一个应用服务方法是一个工作单元,具有原子性。

大多数横切关注点在ABP框架中自动实现或按照约定实现,无需额外编写代码。

通用原则

在进入DDD之前,让我们梳理下DDD通用原则。

数据库(Database Provider / ORM)独立性原则

领域层和应用层不知道项目中使用的 ORM 和 Database Provider。只依赖于仓储接口,并且仓储接口不适合使用用任何 ORM 特殊对象

这一原则的主要原因是:

1.使领域层和应用层与基础层独立,因为基础层将来可能更改,或者你可能需要支持其他类型数据库。2.使领域和应用聚焦在业务代码上,通过将基础设施实现细节隐藏于仓储之后,使您的领域和应用服务专注于业务代码。3.易于自动化测试,因为可以通过仓储接口模拟仓储数据。

根据这一原则,除启动应用程序外,解决方案中的任何项目都没有引用 EntityFrameworkCore 项目。

关于数据库独立性原则的讨论

尤其是原因1会深深地影响你的领域对象设计(比如,实体关系)和应用层代码。假设你当前使用 Entity Framework Core 操作关系型数据库,后期希望切换为 MongoDB,这就决定你不能使用 EF Core 中独有功能,因为在MongoDB中不被支持。

举个例子:

•不能使用更改跟踪(Change Tacking),因为 MongoDB 不支持。所以,需要显式更改实体。•不能在实体中使用导航属性(Navigation Properties) 或集合关联其他聚合,因为可能在文档数据库中不支持。

那么如何解决实体关联的问题?记住规则:仅通过Id引用其他聚合。

如果你认为这些功能对你很重要,而且你永远不会弃用 EF Core,我们认为这个原则是可以有弹性的,但是我们仍然建议使用仓储模式来隐藏基础设施的实现细节。

ABP Framework 为仓储接口 IRepository 提供获取 IQueryable 对象的扩展方法 GetQueryableAsync(),使我们在使用仓储时可以直接使用标准LINQ扩展方法

展示技术无关性原则

展示层技术(UI框架)是应用程序中变化最多的部分,将领域层和应用层设计成完全不知道展示层技术或框架是非常重要的。

这一原则相对容易实现,而ABP的启动模板使其更加容易实现,选择不同UI框架自动生成对应的启动模板项目。

在某些场景下,你可能需要在应用层和展示层使用相同的逻辑。举例,你可能需要在两个层中进行验证和授权。在UI层检测是为了提高用户体验,在应用层和领域层是出安全和数据有效性考虑。这是非常正常和必要的。

聚焦状态变化,而不是性能优化

DDD聚焦领域对象如何变化和如何交互;如何创建实体和改变属性,并且保持数据的完整性、有效性;如何创建方法,实现业务规则。

DDD没有考虑报表大规模查询等需要高性能的业务场景,如果你的应用程序中没有花哨的仪表盘或报表功能,谁会去考虑呢?意思是我们需要自己考虑性能问题。

性能优化或技术选型,只要不影响到业务逻辑,可以自由使用 SQL Server 全部功能,比如:查询优化、索引、存储过程等技术;甚至使用一个其他数据源,如:ElasticSearch,来负责报表功能。

学习帮助

围绕DDDABP Framework两个核心技术,后面还会陆续发布核心构件实现综合案例实现系列文章,敬请关注!

ABP Framework 研习社(QQ群:726299208) ABP Framework 学习及实施DDD经验分享;示例源码、电子书共享,欢迎加入!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/301219.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

伦敦科学博物馆用百年智慧打造的一套探索书,拓展孩子的科学、数学和艺术思维...

▲数据汪特别推荐点击上图进入玩酷屋说到素质教育,我们应该比较熟悉。不过,这几年,比素质教育更火的一个概念是——STEAM教育。教育家们普遍认为:在科学、技术、工程、艺术、数学之间存在着一种相互支撑、相互补充、共同发展的关系…

java中事务特性_「java三分钟」事务的传播特性详解

关注我,每天三分钟,带你轻松掌握一个Java相关知识点。事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。换言之,一个带事务的方法调用了另一个带事务的方法,被调用的方法它怎么处理自己事务和调用方…

基于ABP落地领域驱动设计-02.聚合和聚合根的最佳实践和原则

前言上一篇 基于ABP落地领域驱动设计-01.全景图 概述了DDD理论和对应的解决方案、项目组成、项目引用关系,以及基于ABP落地DDD的通用原则。从这本篇开始,会更加深入地介绍在基于 ABP Framework 落地DDD过程中的最佳实践和原则。围绕DDD和ABP Framework两…

每日一笑 | 实名举报校长拿两份工资!

全世界只有3.14 % 的人关注了数据与算法之美(图源网络,侵权删)

159个故事串起三千年大历史!这套“儿童版史记”太无敌了!

▲数据汪特别推荐点击上图进入玩酷屋17世纪英国哲学家培根说“读史使人明智”,意思是真实、鲜活的历史,不仅能极大拓宽孩子眼界,更能让孩子以古人为鉴,树立远大的志向,对成长大有助益。在我们的学生时代,认…

再见,REST,你好,gRPC

gRPC是一个开源的远程过程调用框架,用于服务之间的高性能通信。服务之间的通信可以使用各种语言,通过可插拔的负载均衡、追踪、健康检查和身份验证,这让它被认为是一种非常高效的方法。在默认情况下,gRPC使用协议缓冲(…

全校师生放6天春假;清华大学设立天文系;郭守敬望远镜光谱数突破千万;《自然》发表最新发现;百度败诉需道歉;这就是今天的大新闻...

今天是3月29日农历二月廿三今天星期五早上上班等了N趟车愣是没挤上去下面是今天的大新闻全校师生放6天“春假”(中国青年网)3月28日,四川西南航空职业学院发布了《关于“泛美春假”的放假通知》,要求在放假时间总量不变的情况下&a…

jenkins java反序列化_Jenkins “Java 反序列化”过程远程命令执行漏洞

###漏洞原理反序列化是指特定语言中将传递的对象序列化数据重新恢复为实例对象的过程,而在这个过程中会执行一系列的字节流解析和对象实例化操作用于恢复之前序列化时的对象。在原博文所提到的那些 Java 应用里都有特定的接口用于传递序列化对象数据,而在…

WPF DataGrid 在Header中显示行号

在Datagrid中显示行号&#xff0c;如果你绑定的datacontext中没有序号&#xff0c;又想要显示序号的时候&#xff0c;可以按照本文的方法显示喽~效果如下图&#xff1a;来看看代码吧~MainWindow.xaml<Window x:Class"wpfcore.MainWindow"xmlns"http://schema…

每日一笑 | 爱的魔力转圈圈~

全世界只有3.14 % 的人关注了数据与算法之美&#xff08;素材源网络&#xff0c;侵权删&#xff09;

怎样维护成功的开源项目

开源可不仅仅是将代码扔到网上就万事大吉了&#xff0c;将开源项目变成能让自己引以为豪的东西才算成功。那么&#xff0c;你需要注意哪些方面呢&#xff1f; 写好指导性文字 每一个开源项目有三样东西是少不了的&#xff1a;项目目标和方法的简要说明、如何参与和授权许可。最…

技术管理中的手段——奖励和惩罚

对于技术出身的同学来说&#xff0c;一旦晋升为管理岗&#xff0c;则意味着面临很多棘手的问题&#xff0c;例如&#xff1a;手下的人不听管教&#xff0c;无法按时完成任务等等。一般凭技术晋升的同学&#xff0c;自然是技术中的佼佼者&#xff0c;作为团队中的骨干&#xff0…

用科学实验玩“坏”二十四节气,中华传统还能这么学,科学、节气、民俗三重启蒙!...

▲数据汪特别推荐点击上图进入玩酷屋之前我们“迪比的冒险之旅”和“delightmom魔幻科学实验”做完团购活动之后&#xff0c;很多妈妈都跟小木说拿回去孩子特别喜欢&#xff0c;每个实验做了好几遍还不尽兴&#xff0c;经常追问小木有没有新的实验更新。看下图孩子玩的多么开心…

java 1.8 vm_HotSpot虚拟机在java 1.8中的新实现

HotSpotJava HotSpot 虚拟机是 Java SE 平台的一个核心组件。它实现 Java 虚拟机规范&#xff0c;并作为 Java 运行时环境中的一个共享库来提供。作为 Java 字节码执行引擎&#xff0c;它在多种操作系统和架构上提供 Java 运行时设施&#xff0c;如线程和对象同步。它包括自适应…

用BenchmarkDotNet看Method

在前面的文章中看了Property的几种不同访问方式《用BenchmarkDotNet看Property》&#xff0c;性能调用上的差别明显&#xff0c;那同样作为class里重要成员&#xff0c;Method性能如何呢&#xff1f;下面是被测试方法public class MyClass{public string MyMethod(){return Dat…

美国老师用的思维导图书,真正培养孩子的思维能力!

▲数据汪特别推荐点击上图进入玩酷屋小木读大学的时候&#xff0c;无意间在图书馆接触到了东尼博赞的《思维导图》。当时有好几个朋友和我推荐过这本书&#xff0c;我就借来看了。阅读之后&#xff0c;我发现对我来说&#xff0c;这真是不可多得一本好书——它改变了我20多年的…

filesystemwatch java_C#方法的委托和java中的回调

先看个效果20130415.C#监视文件夹,显示文件夹操作到listView上代码实现,以前在学校生活写的,就几句代码using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;us…

每日一笑 | 为什么男生追到一半就不追了?

全世界只有3.14 % 的人关注了数据与算法之美&#xff08;图源网络&#xff0c;侵权删&#xff09;

转:超越设计模

转&#xff1a;http://www.ibm.com/developerworks/cn/java/j-lo-beyondpattern/刘 旭进, 软件开发工程师, IBM 中国软件开发中心简介&#xff1a; 可复用面向对象软件的基础 -- 设计模式&#xff0c;以其可复用的设计初衷、精巧的逻辑思维被广大面向对象程序设计所追捧。但不少…

为什么中国天才都往美国跑,可美国人的数学那么槽糕

中国天才少年尹希&#xff0c;17岁时收到哈佛大学博士offer&#xff0c;31岁成为哈佛最年轻华人正教授。中国年轻科学家、未来科学大奖数学与计算机奖获得者许晨阳&#xff0c;于2018年加入美国麻省理工&#xff0c;选择去世界顶尖的地方看看。22岁中国“神童”曹原&#xff0c…