基于ABP落地领域驱动设计-06.正确区分领域逻辑和应用逻辑

系列文章

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

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

基于ABP落地领域驱动设计-03.仓储和规约最佳实践和原则

基于ABP落地领域驱动设计-04.领域服务和应用服务的最佳实践和原则

基于ABP落地领域驱动设计-05.实体创建和更新最佳实践

围绕DDDABP Framework两个核心技术,后面还会陆续发布核心构件实现综合案例实现系列文章,敬请关注! ABP Framework 研习社(QQ群:726299208) ABP Framework 学习及实施DDD经验分享;示例源码、电子书共享,欢迎加入!

领域逻辑和应用逻辑

正如前面提到的,领域驱动设计中的业务逻辑拆分为两部分:领域逻辑应用逻辑

领域逻辑由系统的核心领域规则组成,而应用程序逻辑实现特定于应用程序的用例。

虽然定义很清楚,但实现可能并不容易,常常无法决定哪些代码应该放在应用层,哪些代码应该放在领域层。本节试图解释这些差异。

多应用层

当你的系统很大时,DDD有助于处理复杂性问题。特别是,在一个领域中开发多个应用,那么领域逻辑与应用逻辑的分离就变得更加重要。

假设你正在构建一个有多个应用程序的系统:

•一个Web应用程序,使用 ASP .NET Core MVC,展示产品给用户。浏览产品,不需要进行身份验证;只有当用户执行某些操作时,比如向购物车中添加产品,才会要求登陆。•一个后台管理应用程序,使用Angular UI+ REST APIs构建。此应用由公司办公人员做系统管理,比如:编辑产品描述。•一个移动应用程序,和 Web应用程序 相比UI更加简单,通过REST APIs或其他技术(如:TCP/Socket)与服务器通信。

每一个应用都需要解决不同的需求,实现不同用例(应用服务方法),不同DTO,不同验证和授权规则等等。

将所有这些逻辑混合到一个应用层中,将使你的服务包含太多的判断条件和复杂的业务逻辑,使代码更难开发、维护和测试,并导致潜在的Bug。

如果你有单个领域关联多个应用程序:

•为每个应用程序或客户端创建单独的应用层,在这些单独层中实现特定于应用的业务逻辑。•使用单个领域层共享核心领域逻辑

这样的设计使得区分领域逻辑应用逻辑变得更加重要。

为了更清楚地实现,可以为每种应用程序类型创建不同的项目(.csproj)。

例如:

•后台管理应用创建 IssueTracker.Admin.Application 和 IssueTracker.Admin.Application.Contracts 项目•WEB应用创建 IssueTracker.Public.Application 和 IssueTracker.Public.Application.Contracts•移动应用创建 IssueTracker.Mobile.Application 和 IssueTracker.Mobile.Application.Contracts

示例:正确区分应用逻辑和领域逻辑

本节包含一些应用服务和领域服务示例,讨论如何决定在这些服务中放置业务逻辑。

示例:在领域服务中创建 Organization (组织)

public class OrganizationManager:DomainService
{private readonly IRepository<Organization> _organizationRepository;private readonly ICurrentUser _currentUser;private readonly IAuthorizationService _authorizationService;private readonly IEmailSender _emailSender;public OrganizationManager(IRepository<Organization> organizationRepository,ICurrentUser currentUser,IAuthorizationService authorizationService,IEmailSender emailSender){_organizationRepository=organizationRepository;_currentUser=currentUser;_authorizationService=authorizationService;_emailSender=emailSender;}//创建组织public async Task<Organization> CreateAsync(string name){//检测是否存在同名组织,存在则抛出异常。if(await _organizationRepository.AnyAsync(x=>x.Name==name)){throw new BusinessException("IssueTracking:DuplicateOrganizationName");}//检测是否拥有创建权限await _authorizationService.CheckAsync("OrganizationCreationPermission");//记录日志Logger.LogDebug($"Creating organization {name} by {_currentUser.UserName}");//创建组织实例var organization = new Organization();//发送提醒邮件await _emailSender.SendAsync("systemadmin@issuetracking.com","新组织","新组织名称:"+name);//返回组织实例return organization;}
}

让我们一步一步来分析 CreateAsync 方法中的代码是否都应该放在领域服务中:

•正确:组织名重复检测,存在重复名称则抛出异常。该检测与核心领域规则相关,不允许重名。•错误:领域服务不应该进行权限验证。权限验证应该放在应用层。•错误:记录日志包含当前用户的用户名。领域服务不应该依赖当前用户,当前用户(Session)应该是展示层或应用层中的相关概念。•错误:创建新组织发送邮件,我们仍然认为这是业务逻辑。可以能会根据用例来创建不同类型邮件。

示例:在应用层创建新组织

public class OrganizationAppService:ApplicationService
{private readonly OrganizationManager _organizationManager;private readonly IPaymentService _paymentService;private readonly IEmailSender _emailSender;public OrganizaitonAppService(OrganizationManager organizationManager,IPaymentService paymentService,IEmailSender emailSender){_organizationManager=organizationManager;_paymentService=paymentService;_emailSender=emailSender;}[UnitOfWork][Authorize("OrganizationCreationPermission")]public async Task<Organization> CreateAsync(CreateOrganizationDto input){//支付组织费用await _paymentService.ChargeAsync(CurrentUser.Id,GetOrganizationPrice());//创建组织实例var organization = await _organizationManager.CreateAsync(input.Name);//保存组织到数据库await _organizationManager.InsertAsync(organization);//发送提醒邮件await _emailSender.SendAsync("systemadmin@issuetracking.com","新组织","新组织名称:"+name);//返回实例return organization;}private double GetOrganizationPrice(){return 42;//Gets form somewhere...}
}

让我们看看 CreateAsync 方法,一步一步讨论其中的代码是否应该放在应用服务:

•正确:应用服务方法应该是工作单元,ABP框架工作单元系统自动实现,可以不用添加[UnitOfWork]特性。•正确:权限验证应该放在应用层,可以使用 [Authorize] 特性。•正确:在我们的业务逻辑中创建组织是付费服务,当前操作调用基础设施服务进行支付操作。•正确:应用服务方法负责保存变更到数据库。•正确:给系统管理员发送邮件通知。•错误:不能返回实体,应该返回DTO。

讨论:为什么我们不应该将支付逻辑放在领域服务中?

你可能想知道为什么付款代码不在 OrganizationManager 里面。这是一件很重要的事情,我们绝不希望付款出错。

然而,业务的重要性并不意味着要将其视为核心业务逻辑。我们可能有其他的支付用例,在这些用例中,我们不收取费用来创建一个新的组织。

例如:

•后台办公系统中的管理员用户可以创建新组织,不用考虑支付。•系统数据导入、整合、同步,也可能需要在没有任何支付操作的情况下,创建组织。

如您所见,支付不是创建一个有效组织的必要操作。它是一个特定于用例的应用逻辑。

示例:CRUD操作

public class IssueAppService
{private readonly IssueManager _issueManager;public IssueAppService(IssueManager issueManager){_issueManager=issueManager;}public async Task<IssueDto> GetAsync(Guid id){return await _issueManager.GetAsync(id);}public async Task CreateAsync(IssueCreationDto input){await _issueManager.CreateAsync(input);}public async Task UpdateAsync(UpdateIssueDto input){await _issueManager.UpdateAsync(input);}public async Task DeleteAsync(Guid id){await _issueManager.DeleteAsync(id);}
}

应用服务并没有做任何事情,而是委托给领域服务来处理。只接收DTO参数,并传递给 IssueManger 。

•不要创建只实现简单 CRUD 操作的领域服务方法,而不带任何领域逻辑。•不要传递 DTO 给领域服务,或领域服务方法返回 DTO。

应用服务可以直接使用仓储,实现查询、创建、更新或删除数据,除非执行这些操作时需要处理领域逻辑,这种情况下,创建领域服务方法,但只针对那些真正需要的方法。

不要因为将来可能会需要这些CRUD领域服务方法,就去提前创建这些方法! 当需要时再去创建,并重构现有的代码。由于抽象了应用层,重构领域层不会影响到UI层和其他客户端。

学习帮助

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

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

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

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

相关文章

基于ABP落地领域驱动设计-03.仓储和规约最佳实践和原则

dotNET兄弟会 专注.Net开源技术及跨平台开发&#xff01;致力于构建完善的.Net开放技术文库&#xff01;为.Net爱好者提供学习交流家园&#xff01;公众号 围绕DDD和ABP Framework两个核心技术&#xff0c;后面还会陆续发布核心构件实现、综合案例实现系列文章&#xff0c;敬请…

我国最新十大黑科技发布,颠覆你的想象!

全世界只有3.14 % 的人关注了数据与算法之美人工智能的飞速发展&#xff0c;让“黑科技”一词深入人心。目不暇接的各种前沿技术&#xff0c;一再刷新人们的认知世界。所谓“黑科技”&#xff0c;不仅仅要够炫酷&#xff0c;更要有足够的“生活温度”&#xff0c;实现真正的人性…

基于ABP落地领域驱动设计-04.领域服务和应用服务的最佳实践和原则

围绕DDD和ABP Framework两个核心技术&#xff0c;后面还会陆续发布核心构件实现、综合案例实现系列文章&#xff0c;敬请关注&#xff01; ABP Framework 研习社&#xff08;QQ群&#xff1a;726299208&#xff09; ABP Framework 学习及实施DDD经验分享&#xff1b;示例源码、…

嗓子痛引发大抢救!33岁程序员的垂死经历,为所有人敲响警钟!

全世界只有3.14 % 的人关注了数据与算法之美最近广州天气多变&#xff0c;再加上不规律的饮食、作息&#xff0c;数据汪的扁桃体已经肿痛两三天了。在一大杯“凉茶”下肚后&#xff0c;最终我还是选择去医院做一次检查。万幸的是&#xff0c;检查结果出来后&#xff0c;医生说只…

.NET也内卷了,BAT大厂近日上演抢人大战!

这两年到处都流行“内卷”这个词&#xff0c;而IT互联网行业则是内卷重灾区。还不太明白什么是内卷&#xff1f;看看这个段子&#xff1a;关于内卷&#xff0c;网上有个比喻&#xff0c;说如果葵花宝典被公开了&#xff0c;就会变成一个灾难。因为如果只有一个人拥有的话&#…

EFDC水模型 初学者入门 及软件下载学习指导

EFDC模型有三个不同的版本&#xff0c;它们分别代表了计算机不同的操作菜单和功能。其中的两个版本功能齐全&#xff0c;包括了EFDC 所有的产品版本。另外一个是简化版&#xff0c;涵盖了水动力学&#xff08;包括盐度和温度的影响&#xff09;&#xff0c;毒物&#xff0c;沉积…

每日一笑 | 在地铁上被老奶奶让座是一种什么样的体验?

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

java access dbq_Java-Access汇总

http://www.doczj.com/doc/3b7b55100b4e767f5acfce38.html/view/d1c01b43a8956bec0975e33e.html在网上看了一些资料&#xff0c;基本上都是一样的。怎么试也行不通。于是我怀疑为什么那些错误的技术文章如此大张旗鼓的到处都是。今天有人问我如果把主机托管出去&#xff0c;也就…

一个IT人的非典型职场十年 (5)

2019独角兽企业重金招聘Python工程师标准>>> 对于非资深IT人来讲&#xff0c;IT咨询(IT Consulting)显得是比较高帅富一些&#xff0c;各种衣着光鲜的咨询报告&#xff0c;各种西装革履的顾问。 这先随便说两句什么是IT咨询&#xff0c;IT顾问究竟是在做啥工作。 I…

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

什么是领域驱动&#xff1f;领域驱动设计&#xff08;简称&#xff1a;DDD&#xff09;是一种针对复杂需求的软件开发方法。将软件实现与不断发展的模型联系起来&#xff0c;专注于核心领域逻辑&#xff0c;而不是基础设施细节。DDD适用于复杂领域和大规模应用&#xff0c;而不…

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

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

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

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

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

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

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

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

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

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

再见,REST,你好,gRPC

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

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

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

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

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

WPF DataGrid 在Header中显示行号

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

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

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