Abp vNext 基础篇丨分层架构
介绍
本章节对 ABP 框架进行一个简单的介绍,摘自ABP官方,后面会在使用过程中对各个知识点进行细致的讲解。
领域驱动设计
领域驱动设计(简称:DDD)是一种针对复杂需求的软件开发方法。将软件实现与不断发展的模型联系起来,专注于核心领域逻辑,而不是基础设施细节。DDD适用于复杂领域和大规模应用,而不是简单的CRUD应用。它有助于建立一个灵活、模块化和可维护的代码库。
一个基于领域驱动的解决方案有四个基本层:
领域层:实现领域(或系统)中的用例独立的核心业务逻辑。
应用层:基于领域的应用程序用例,应用程序用例可以看作是用户界面上的用户交互。
展示层:包含应用程序UI元素(页面、组件等)。
基础层:支持层,通过对第三方类库的调用或系统的抽象和集成来实现对其他层的支持。
核心构件
DDD主要关注领域层和应用层,展示层和基础层被看作是细节,业务层不应该依赖于它们,但这并不意味着展示层和基础层不重要,它们也非常重要。展示层中的UI框架和基础层中的数据提供程序有他们自己的实现规则和最佳实践,需要了解和应用。然而,这些并不在DDD的主题中,我们重点来看领域层和应用层的基本构件。
领域层构件
实体(Entity):一个实体是一个对象,该对象包含自己的属性和方法,属性用于存储数据和描述状态;方法结合属性实现业务逻辑。一个实体使用唯一标识(ID)来表示,两个实体对象ID不同则是为不同的实体。
值对象(Value Object):值对象是另一种类型的领域对象,该对象由其属性而不是唯一ID来标识。意思是说,只有全部属性相同才会被认为是同一个对象。值对象通常被实现为不可变的,而且大多比实体简单得多。
聚合和聚合根:聚合根是一个特定类型的实体,具有额外的职责。聚合是以聚合根为中心绑定在一起的一组对象,对象包括实体和值对象。
仓储(接口):仓储是一个类似集合的接口,被领域层和应用层用来访问数据持久化系统(数据库)。它将数据库的复杂性从业务代码中隐藏起来。领域层包含仓储接口。
领域服务:领域服务是无状态服务,实现核心领域业务规则。用于实现依赖于多个聚合(实体)或外部服务的领域逻辑。
规约:用于为实体和其他业务对象定义可命名的、可重用的和可组合的过滤器。
领域事件:领域事件是一种低耦合的通知方式,当一个特定的领域事件发生时,会通知其他服务。
应用层构件
应用服务:应用服务是无状态服务,实现应用程序用例。一个应用服务通常获取和返回数据传输对象(DTOs),用于展示层。调用领域对象来实现用例。一个用例通常被认为是一个工作单元。
数据传输对象(DTO):DTO是简单对象,不包含任何业务逻辑,只用于在应用层和展示层传递数据。
工作单元:一个工作单元是一个原子工作。在工作单元中的所有操作统一提交,要么全部成功,失败则全部回滚。
ABP项目分层解析
领域层
领域层拆分为两个项目:
Bcvp.Blog.Core.Domain:领域层,该项目包含所有领域层构件,比如:实体、值对象、领域服务、规约、仓储接口等。
Bcvp.Blog.Core.Domain.Shared:领域共享层,包含属于领域层,但是与其他层共享的类型。举个例子:定义的常量和枚举,既在领域对象中使用,也要在其他层中使用,放在该项目中。
应用层
应用层拆分为两个项目:
Bcvp.Blog.Core.Application.Contracts:应用契约层,包含应用服务接口和数据传输对象(用于接口),该项目被应用程序客户端引用,比如:WEB项目、API客户端项目。
Bcvp.Blog.Core.Application:应用层,实现在 Contracts 项目中定义的接口。
展示层
Bcvp.Blog.Core.HttpApi.Host 项目作为一个独立的端点提供 HTTP API 服务,供客户端调用。
远程服务层
Bcvp.Blog.Core.HttpApi:远程服务层,该项目用于定义 HTTP APIs,通常包含 MVC Controller 及相关的模型。
Bcvp.Blog.Core.HttpApi.Client:远程服务代理层,客户端应用程序引用该项目,将直接通过依赖注入使用远程应用服务,该项目基于ABP Framework动态C#客户端API代理系统实现。在C#项目中需要调用HTTP APIs时,会非常有用。
基础层
实现DDD时,可以使用一个基础层项目来实现所有的集成和抽象,当然也可以为不同依赖创建不同项目。
建议折中处理,为核心基础依赖创建单独项目,比如:Entity Framework Core;另外创建一个公共基础项目存放其他基础设施。
启动模板中包含两个项目对 Entity Framework Core 进行集成:
Bcvp.Blog.Core.EntityFrameworkCore:EF Core核心基础依赖项目,包含:数据上下文、数据库映射、EF Core仓储实现等。
其他项目
还有一个项目 Bcvp.Blog.Core.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 项⽬,可以在⻚⾯/组件中使⽤应⽤服务
DDD通用原则
在正式开始之前我们在梳理一下DDD的通用原则。
数据库(Database Provider / ORM)独⽴性原则
领域层和应⽤层不知道项⽬中使⽤的 ORM 和 Database Provider。只依赖于仓储接⼝,并且仓储接⼝ 不适合使⽤⽤任何 ORM 特殊对象
这⼀原则的主要原因是:
使领域层和应⽤层与基础层独⽴,因为基础层将来可能更改,或者你可能需要⽀持其他类型数据库。
使领域和应⽤聚焦在业务代码上,通过将基础设施实现细节隐藏于仓储之后,使您的领域和应⽤服 务专注于业务代码。
易于⾃动化测试,因为可以通过仓储接⼝模拟仓储数据。
关于数据库独⽴性原则的讨论
假设你当前使⽤ 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 全部功能。
结语
本节知识点:
- 1.讲解Abp和DDD的分层架构介绍
- 2.很重要的知识点DDD聚焦状态变化而非性能优化
联系作者:加群:867095512 @MrChuJiu
Abp vNext 基础篇丨分层架构的更多相关文章
- 五、Abp vNext 基础篇丨博客聚合功能
介绍 业务篇章先从客户端开始写,另外补充一下我给项目起名的时候没多想起的太随意了,结果后面有些地方命名冲突了需要通过手动using不过问题不大. 开工 应用层 根据第三章分层架构里面讲到的现在我们模型 ...
- 六、Abp vNext 基础篇丨文章聚合功能上
介绍 9月开篇讲,前面几章群里已经有几个小伙伴跟着做了一遍了,遇到的问题和疑惑也都在群里反馈和解决好了,9月咱们保持保持更新.争取10月份更新完基础篇. 另外番外篇属于 我在abp群里和日常开发的问题 ...
- 十一、Abp vNext 基础篇丨测试
前言 祝大家国庆快乐,本来想国庆之前更新完的,结果没写完,今天把剩下的代码补了一下总算ok了. 本章节也是我们后端日常开发中最重要的一步就是测试,我们经常听到的单元测试.集成测试.UI测试.系统测试, ...
- 七、Abp vNext 基础篇丨文章聚合功能下
介绍 不好意思这篇文章应该早点更新的,这几天在忙CICD的东西没顾得上,等后面整好了CICD我也发2篇文章讲讲,咱们进入正题,这一章来补全剩下的 2个接口和将文章聚合进行完善. 开工 上一章大部分业务 ...
- Abp vNext 基础篇丨领域构建
介绍 我们将通过例⼦介绍和解释⼀些显式规则.在实现领域驱动设计时,应该遵循这些规则并将其应⽤到解决⽅案中. 领域划分 首先我们先对比下Blog.Core和本次重构设计上的偏差,可以看到多了一个博客管理 ...
- 八、Abp vNext 基础篇丨标签聚合功能
介绍 本章节先来把上一章漏掉的上传文件处理下,然后实现Tag功能. 上传文件 上传文件其实不含在任何一个聚合中,它属于一个独立的辅助性功能,先把抽象接口定义一下,在Bcvp.Blog.Core.App ...
- 十、Abp vNext 基础篇丨权限
介绍 本章节来把接口的权限加一下 权限配置和使用 官方地址:https://docs.abp.io/en/abp/latest/Authorization 下面这种代码可能我们日常开发都写过,ASP. ...
- 九、Abp vNext 基础篇丨评论聚合功能
介绍 评论本来是要放到标签里面去讲的,但是因为上一章东西有点多了,我就没放进去,这一章单独拿出来,内容不多大家自己写写就可以,也算是对前面讲解的一个小练习吧. 相关注释我也加在代码上面了,大家看看代码 ...
- Abp vNext 番外篇-疑难杂症丨浅谈扩展属性与多用户设计
说明 Abp vNext基础篇的文章还差一个单元测试模块就基本上完成了我争取10.1放假之前给大家赶稿出来,后面我们会开始进阶篇,开始拆一些东西,具体要做的事我会单独开一个文章来讲 缘起 本篇文章缘起 ...
随机推荐
- C++智能指针之shared_ptr与右值引用(详细)
1. 介绍 在 C++ 中没有垃圾回收机制,必须自己释放分配的内存,否则就会造成内存泄露.解决这个问题最有效的方法是使用智能指针(smart pointer).智能指针是存储指向动态分配(堆)对象指针 ...
- shell下读取文件数据
参考:https://www.imzcy.cn/1553.html while和for对文件的读取是有区别的: 1. for对文件的读是按字符串的方式进行的,遇到空格什么后,再读取的数据就会换行显示 ...
- 一千个不用 Null 的理由!
港真,Null 貌似在哪里都是个头疼的问题,比如 Java 里让人头疼的 NullPointerException,为了避免猝不及防的空指针异常,千百年来程序猿们不得不在代码里小心翼翼的各种 if 判 ...
- 从三道题目入门frida
偶然从看雪看到了一篇入门frida的题目,正好苦于没练手的东西,直接上手一波 1.第一题jadx打开,也没有壳和混淆,整体非常清晰,判断的逻辑也很简单 发现其实就是两个输入框,一个用户名一个密码,先拼 ...
- .Net Core微服务——服务发现:Consul(一)
先思考一些问题:它是做什么的.以及怎么使用它.带着这些问题往下走. consul是做什么的 consul用于微服务下的服务治理.服务治理是什么?它包含但不限于:服务发现.服务配置.健康检查.键值存储. ...
- 远程cmd操作
<<PSTools.zip>><<Install_PowerCmd.exe>><<cmder_mini.zip>><< ...
- c++中的继承关系
1 什么是继承 面向对象的继承关系指类之间的父子关系.用类图表示如下: 2 为什么要有继承?/ 继承的意义? 因为继承是面向对象中代码复用的一种手段.通过继承,可以获取父类的所有功能,也可以在子类中重 ...
- 前端-Vue基础2
1.过滤器 前台通过后台传值,要对后台传过来的变量进行特殊处理,比如根据id转成中文等: 1.1 局部过滤器 局部过滤器只针对一个Vue实例 默认将|左侧count传递给右侧方法 {{count|fi ...
- POJ 博弈论
poj1704 Georgia and Bob 题目链接:http://poj.org/problem?id=1704 题意:如图所示,两个人在玩一个游戏,排成直线的格子上有n个棋子,两人依次将棋子向 ...
- 跟我一起学Go系列:gRPC 全局数据传输和超时处理
gRPC 在多个 GoRoutine 之间传递数据使用的是 Go SDK 提供的 Context 包.关于 Context 的使用可以看我之前的一篇文章:Context 使用. 但是 Context ...