ABP入门系列(18)—— 使用领域服务

1.引言

自上次更新有一个多月了,发现越往下写,越不知如何去写。特别是当遇到DDD中一些概念术语的时候,尤其迷惑。如果只是简单的去介绍如何去使用ABP,我只需参照官方文档,实现到任务清单Demo中去就可以了,不劳神不费力。但是,这样就等于一知半解。

知之为知之,不知为不知,是知也。知其然知其所以然,方能举一反三嘛。

为了揭开迷惑,最近开始研读《实现领域驱动设计》去学习DDD中的思想,并开了一个DDD专题去记录我学习的成果。欢迎大家关注,共同学习进步并不吝赐教!

后续的文章我会继续保持之前的书写风格,并适当穿插一些对DDD中的概念的理解,来加深对ABP框架的学习。

2.用例分析

用户可以无限创建任务但仅能分配给自己;管理员具有分配任务给他人的权限,任务分配成功后要通知接收人。

我们分析下这个业务用例,其实主要涉及到一个业务操作——任务分配。按照我们传统的思路,在做任务分配这个操作时,就是对任务进行编辑,没有什么特别的地方,通过代码调用应用层服务更新Task实体即可。

//TaskAppService.cs
public void UpdateTask(UpdateTaskInput input)
{//We can use Logger, it's defined in ApplicationService base class.Logger.Info("Updating a task for input: " + input);//获取是否有权限bool canAssignTaskToOther = PermissionChecker.IsGranted(PermissionNames.Pages_Tasks_AssignPerson);//如果任务已经分配且未分配给自己,且不具有分配任务权限,则抛出异常if (input.AssignedPersonId.HasValue && input.AssignedPersonId.Value != AbpSession.GetUserId() ){if (!canAssignTaskToOther)throw new AbpAuthorizationException("没有分配任务给他人的权限!");else{var updateTask = Mapper.Map<Task>(input);_taskRepository.Update(updateTask);//发送通知var message = "You hava been assigned one task into your todo list.";_smtpEmailSender.Send("ysjshengjie@qq.com", updateTask.AssignedPerson.EmailAddress, "New Todo item", message);_notificationPublisher.Publish("NewTask", new MessageNotificationData(message), null,NotificationSeverity.Info, new[] { updateTask.AssignedPerson.ToUserIdentifier() });}}
}

以上代码也能满足以上需求,但是这已经违背了ABP分层架构的思想,其实也就是违背了DDD的思想。

应用层不包含业务逻辑,而我们的UpdateTask方法明显承载了太多的业务,既要检查权限又要发送通知。
那可如何是好?自然是在领域服务去处理这些业务逻辑了。

这里就引入了DDD中的两个概念,应用服务和领域服务,我们有必要先来介绍一下,之后再来用领域服务来改造。

3.应用服务VS领域服务

应用服务对应的是应用层,领域服务对应的领域层。它们之间主要的区别在于是否处理业务逻辑。那这个限制从何而来呢?DDD的分层架构思想。

DDD使用的传统分层架构

  • 用户接口层(Presentation):提供一个用户界面,实现用户交互操作。
  • 应用层(Application):进行展现层与领域层之间的协调,协调业务对象来执行特定的应用程序的任务。它不包含业务逻辑。
  • 领域层(Domain):包括业务对象和业务规则,这是应用程序的核心层。
  • 基础设施层(Infrastructure):提供通用技术来支持更高的层。例如基础设施层的仓储(Repository)可通过ORM来实现数据库交互。

应用服务作为领域服务的消费方,领域服务是无状态的(领域对象具有状态和行为,而领域服务是用来处理业务逻辑的,它本身是一个行为,所以是无状态的)。领域服务是用来协调领域对象完成某个操作,状态由领域对象保存。

上面也说了,领域对象是具有状态和行为的。那就是说我们也可以在实体或值对象来处理业务逻辑。那我们该如何取舍呢?
一般来说,在下面的几种情况下,我们可以使用领域服务:

  1. 执行某个具体的业务操作。
  2. 领域对象的转换。
  3. 以多个领域对象为输入,返回一个值对象。

4. 使用领域服务

经过上面的分析,很显然我们的用例,使用领域服务来实现更合适。
ABP中定义了IDomainService接口,按约定所有的领域服务都要实现它,实现之后,领域服务被自动暂时的注册到依赖注入系统。
同样,领域服务也可以从DomainService类继承,因此它可以使用继承得来的日志、本地化、等属性。

这里,我们定义一个ITaskManager(Abp中约定俗成的领域服务命名规则,以Manager结尾,当然你也可以自行命名)来定义我们的领域服务,然后实现它。

namespace LearningMpaAbp.Tasks
{public interface ITaskManager : IDomainService{void AssignTaskToPerson(Task task, User user);}
}

实现的领域服务负责主要的业务逻辑,其中发送通知的业务我定义了一个领域事件去实现。关于领域事件,我们下节再聊。


namespace LearningMpaAbp.Tasks
{public class TaskManager : DomainService, ITaskManager{private readonly IPermissionChecker _permissionChecker;private readonly IAbpSession _abpSession;private readonly IEventBus _eventBus;public TaskManager(IPermissionChecker permissionChecker, IAbpSession abpSession, IEventBus eventBus){_permissionChecker = permissionChecker;_abpSession = abpSession;_eventBus = eventBus;}public void AssignTaskToPerson(Task task, User user){//已经分配,就不再分配if (task.AssignedPersonId.HasValue && task.AssignedPersonId.Value == user.Id){return;}if (task.State != TaskState.Open){throw new ApplicationException("处于非活动状态的任务不能分配!");}//获取是否有【分配任务给他人】的权限bool canAssignTaskToOther = _permissionChecker.IsGranted(PermissionNames.Pages_Tasks_AssignPerson);if (user.Id != _abpSession.GetUserId() && !canAssignTaskToOther){throw new AbpAuthorizationException("没有分配任务给他人的权限!");}task.AssignedPersonId = user.Id;//使用领域事件触发发送通知操作_eventBus.Trigger(new TaskAssignedEventData(task, user));}}
}

定义完领域服务,我们直接在应用服务层调用即可。

public void UpdateTask(UpdateTaskInput input)
{//We can use Logger, it's defined in ApplicationService base class.Logger.Info("Updating a task for input: " + input);//获取是否有权限//bool canAssignTaskToOther = PermissionChecker.IsGranted(PermissionNames.Pages_Tasks_AssignPerson);//如果任务已经分配且未分配给自己,且不具有分配任务权限,则抛出异常if (input.AssignedPersonId.HasValue && input.AssignedPersonId.Value != AbpSession.GetUserId()){var updateTask = Mapper.Map<Task>(input);var user = _userRepository.Get(input.AssignedPersonId.Value);//先执行分配任务_taskManager.AssignTaskToPerson(updateTask, user);//再更新其他字段_taskRepository.Update(updateTask);发送通知//var message = "You hava been assigned one task into your todo list.";//_smtpEmailSender.Send("ysjshengjie@qq.com", updateTask.AssignedPerson.EmailAddress, "New Todo item", message);//_notificationPublisher.Publish("NewTask", new MessageNotificationData(message), null,//    NotificationSeverity.Info, new[] { updateTask.AssignedPerson.ToUserIdentifier() });}
}

更新后UpdateTask方法已经注释掉了权限检查以及发布通知的业务逻辑,整个方法也讲更清晰。

5.总结

这一节没有太难的知识点,我们只需谨记,领域服务和应用服务的区别在于只有领域服务才处理业务逻辑。应用服务作为领域服务的消费方,是很薄的一层。
当然,我们也要记住,过度使用领域服务会导致贫血领域模型(即所有的业务逻辑都位于领域服务中,而不是实体和值对象中)。

推荐链接:你必须知道的.NET Core开发指南 
推荐链接:你必须知道的ML.NET开发指南 
推荐链接:你必须知道的Office开发指南 
推荐链接:你必须知道的IOT开发指南 

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

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

相关文章

mysql文件类型_MyCat教程:实现MySql主从复制

原文&#xff1a;http://iii75.cn/mwQhBW 作者&#xff1a;波波烤鸭历史相关文章Mycat入门教程单个mysql数据库在处理业务的时候肯定是有限的&#xff0c;这时我们扩展数据库的第一种方式就是对数据库做读写分离(主从复制),本文我们就先来介绍下怎么来实现mysql的主从复制操作。…

截屏当前界面_电脑屏幕怎么截取,常见的几种电脑截屏方法

随着科技的快速发展电脑已经逐渐渗入到我们的工作和生活中&#xff0c;我们需要使用电脑的地方也越来越多&#xff0c;电脑已经成为了一种新式的办公工具。今天小编不是向大家介绍电脑的应用&#xff0c;而是想要和大家分享一下关于电脑截图的几种方法。1、Print Screen SysRqP…

ABP入门系列(19)——使用领域事件

1.引言 最近刚学习了下DDD中领域事件的理论知识&#xff0c;总的来说领域事件主要有两个作用&#xff0c;一是解耦&#xff0c;二是使用领域事件进行事务的拆分&#xff0c;通过引入事件存储&#xff0c;来实现数据的最终一致性。若想了解DDD中领域事件的概念&#xff0c;可参…

扩容是元素还是数组_Java中对数组的操作

数组对于每一门编程语言来说都是重要的数据结构之一&#xff0c;当然不同语言对于数组的实现及处理也不尽相同。Java语言中提供的数组是用来存储固定大小的同类型元素。如&#xff1a;声明一个数组变量&#xff0c;numbers[100]来代替直接声明100个独立变量number0,number1,...…

ABP入门系列(20)——使用后台作业和工作者

1.引言 说到后台作业&#xff0c;你可能条件反射的想到BackgroundWorker&#xff0c;但后台作业并非是后台任务&#xff0c;后台作业用一种队列且持久稳固的方式安排一些待执行后台任务。 为执行长时间运行的任务而用户无需等待&#xff0c;以提高用户体验。为创建可重试且持…

加载中_GIS地图在项目中的加载显示

下面我们就来说说如何在应用程序中加载显示GIS地图&#xff0c;首先我们在SuperMap iDesktop 9D(10i)中编辑好我们需要的地图&#xff0c;如下图所示&#xff1a;如上图所示&#xff0c;这是我编辑好的一幅天河区的地图&#xff0c;下面我就以这幅地图为例来说说如何把这样一幅…

ABP入门系列(21)——切换MySQL数据库

1. 引言 Abp支持MySql已经不是什么新鲜事了&#xff0c;但按照官方文档&#xff1a;Entity Framework - MySql Integration来&#xff0c;你未必能成功切换&#xff0c;本文就记录下切换MySql数据库遇到的一些坑&#xff0c;供后人乘凉&#xff01; 2. 环境准备 MySql数据库…

ABP开发框架前后端开发系列---(1)框架的总体介绍

ABP是ASP.NET Boilerplate的简称&#xff0c;ABP是一个开源且文档友好的应用程序框架。ABP不仅仅是一个框架&#xff0c;它还提供了一个最徍实践的基于领域驱动设计(DDD)的体系结构模型。学习使用ABP框架也有一段时间了,一直想全面了解下这个框架的整个来龙去脉&#xff0c;并把…

c++ pdflib输出表格_DescrTab2包,输出SCI级别的描述统计表

今天浏览R包&#xff0c;发现一个不错的包——DescrTab2包。看R包介绍&#xff0c;这个包可以绘制出版物质量级别的描述统计表。看起来很不错。下面来学习下。1. R包安装和加载install.packages("DescrTab2") # 安装包library(DescrTab2) # 加载包2. 加载演示数据集l…

服务器怎么控制忽略样式_使用JavaScript来编写你的CSS样式代码——JSS

介绍JSS是CSS的创作工具&#xff0c;它允许你使用JavaScript以声明&#xff0c;无冲突和可重用的方式描述样式。它可以在浏览器&#xff0c;服务器端或在构建时在Node中编译。JSS与框架无关。它由多个包组成&#xff1a;核心部分&#xff0c;插件以及框架集成等。Githubhttps:/…

Java设计模式、框架、架构、平台之间的关系

1、设计模式 为什么要先说设计模式?因为设计模式在这些概念中是最基本的&#xff0c;而且也比较简单。那么什么是设计模式呢?说的直白点&#xff0c;设计模式就是告诉你针对特定问题如何组织类、对象和接口之间的关系&#xff0c;是前人总结的经验。比如我要在代码中实现一个…

如何学习(记住)linux命令(常用选项)

作者&#xff1a;林果皞 链接&#xff1a;https://www.zhihu.com/question/21690166/answer/66721478 来源&#xff1a;知乎 著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 Unix & Linux 命令行特别之处在于&#xff0c;一些选项的设…

增效工具_【危中寻机】降本增效生存之道 运用IE基础工具提升制造效率

效率提升的利器工业工程IE作为一门学科诞生于美国&#xff0c;却首先在日本得到了最大程度的践行与推广&#xff0c;成为了丰田生产方式TPS及精益制造LP的核心现场IE中的4大核心(工程分析、动作分析、时间分析、布局分析)仍是所有IE的入门工具&#xff0c;被笔者称为“基础IE”…

as将安卓应用打包_Android Studio打包生成apk的方法(超级简单哦)

释放双眼&#xff0c;带上耳机&#xff0c;听听看~&#xff01;打包文件是需要生成APK文件&#xff0c;其他人可以通过APK安装和使用&#xff0c;一般来说&#xff0c;包是指APK生成的发布版本&#xff0c;下文技术狗小编还介绍了Android Studio 超级简单的打包生成apk的方法&a…

Linux中常用的命令都是哪些单词的缩写

作者&#xff1a;蓬岸 Dr.Quest 链接&#xff1a;https://www.zhihu.com/question/49073893/answer/114986798 来源&#xff1a;知乎 著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 417个命令缩写&#xff1a;https://www.abbreviations.co…

ubuntu mysql 防火墙_mysql、ubuntu系统防火墙常规操作

mysql、ubuntu系统防火墙常规操作编辑&#xff1a;006 时间&#xff1a;2020-02-11mysql&#xff1a;数据库操作连接数据库&#xff1a;mysql -u username -p创建数据库&#xff1a;create database databasename;删除数据库&#xff1a;drop database databasename;指定数…

如何轻松记忆Linux文件系统层次结构

Linux对于新手来说非常难学。打好基础对于后面深层次的学习非常重要。 对文件系统层次结构要基本的概念。怎么才能理解并且记忆层级结构呢&#xff1f; 方法/步骤 为了帮助记忆&#xff0c;我做了一个比较清晰的图表来协助层次的记忆。 很多目录文件夹的名字长得非常抽象&…

fmc是fpga直接引出来的吗_家长速看!你还在用“不要和陌生人说话”糊弄孩子的安全教育吗?...

在许多幼儿安全教育案例中&#xff0c;我们都会看到这样一个试验&#xff1a;记者假扮人贩子&#xff0c;利用棒棒糖、零食去诱惑幼儿园的孩子。在其中一次试验中&#xff0c;21个孩子有20个中招&#xff0c;直接跟着陌生人走了。这个试验最终引出来的结论就是要教育孩子不要和…

CentOS 7文件系统与日志分析详解

Linux 文件系统 在处理 Linux 系统出现的各种故障时&#xff0c;故障的症状是最易发现的&#xff0c;而导致这一故障的原因才是最终排除故障的关键。熟悉 Linux 系统中常见的日志文件&#xff0c;了解一般故障的分析与解决办法&#xff0c;将有助于管理员快速定位故障点、“对…

oracle同一个示例两个用户的数据同步_分享两个shell脚本--一键统计Oracle数据库用户信息...

概述今天主要分享一下两个shell脚本&#xff0c;主要是为了查看所有数据库用户及其表空间&#xff0c;统计某个指定用户的明细&#xff0c;下面一起来看看吧~数据库连接脚本use script settdb.sh for DB login details registry#!/bin/bashtmp_username$SH_USERNAMEtmp_passwor…