领域服务

领域服务实现领域逻辑

  • 依赖于服务和存储库。
  • 需要处理多个聚合,因为该逻辑不适合任何聚合。

领域服务与领域对象一起工作。它们的方法可以获取并返回实体、值对象、原始类型……但是,它们不获取/返回dto。dto是应用层的一部分

示例:分配问题给用户

记住问题分配是如何在问题实体中实现的

public class Issue : AggregateRoot<Guid>
{
public Guid? AssignedUserId { get; private set; } public async Task AssignToAsync(AppUser user, IUserIssueService userIssueService)
{
var openIssueCount = await userIssueService.GetOpenIssueCountAsync(user.Id); if(openIssueCount >= 3)
{
throw new BusinessException("IssueTracking:ConcurrentOpenIssueLimit");
} AssignedUserId = user.Id;
} public void CleanAssignment()
{
AssignedUserId = null;
}
}

在这里,我们将把这个逻辑转移到领域服务中。

首先,修改Issue类:

public class Issue : AggregateRoot<Guid>
{
public Guid? AssignedUserId { get; internal set; }
}
  • 删除了与分配问题相关的方法。
  • 将 AssignedUserId 属性的setter从私有改为内部,以允许从领域服务设置它

下一步是创建一个名为 IssueManager 的领域服务,该服务具有AssignToAsync 来将给定问题分配给给定用户

public class IssueManager : DomainService
{
private readonly IRepository<Issue, Guid> _issueReposiroty; public IssueManager(IRepository<Issue, Guid> issueReposiroty)
{
_issueReposiroty = issueReposiroty;
} public async Task AssignToAsync(Issue issue, AppUser user)
{
var openIssueCount = await _issueRepository.CountAsync(i => i.AssignedUserId == user.Id && !i.IsClosed); if(openIssueCount >= 3)
{
throw new BusinessException("IssueTracking:ConcurrentOpenIssueLimit");
} issue.AssignedUserId = user.Id;
}
}

IssueManager 可以注入任何依赖的服务,并用于查询用户的分配问题数量。

我们更喜欢并建议为领域服务使用 Manager 后缀。

这个设计的唯一问题就是 Issue.AssignedUserId 现在在类外开放设置了。然而,它不是公开的。它是内部的,并且只能在同一个程序集中(IssueTracking)进行更改。此示例解决方案的领域项目。我们认为这是合理的

  • 领域层开发人员已经知道领域规则,他们使用 IssueManager
  • 应用层开发人员已经被强制使用IssueManager,他们不直接设置它。

虽然两种方法之间存在权衡,但当业务逻辑需要使用外部服务时,我们更喜欢创建域服务

如果你没有一个好的理由,我们认为没有必要为领域服务创建接口(比如为IssueManager创建IIssueManager)

实现领域驱动设计 - 使用ABP框架 - 领域服务的更多相关文章

  1. 实现领域驱动设计 - 使用ABP框架 - 什么是领域驱动设计?

    前言: 最近看到ABP官网的一本电子书,感觉写的很好,翻译出来,一起学习下 (Implementing Domain Driven Design) https://abp.io/books DDD简介 ...

  2. 实现领域驱动设计 - 使用ABP框架 - 通用准则

    在进入细节之前,让我们看看一些总体的 DDD 原则 数据库提供者 / ORM 无关性 领域和应用程序层应该与 ORM / 数据库提供程序 无关.它们应该只依赖于 Repository 接口,而 Rep ...

  3. 实现领域驱动设计 - 使用ABP框架 - 解决方案概览

    .NET解决方案的分层 下图显示了使用ABP的 应用启动模板 创建的Visual Studio解决方案: 解决方案名称为问题跟踪,它由多个项目组成.通过考虑DDD原则以及开发和部署实践,该解决方案是分 ...

  4. 实现领域驱动设计 - 使用ABP框架 - 存储库

    存储库 Repository 是一个类似于集合的接口,领域层和应用程序层使用它来访问数据持久性系统(数据库),以读写业务对象(通常是聚合) 常见的存储库原则是: 在领域层定义一个存储库接口(因为它被用 ...

  5. 实现领域驱动设计 - 使用ABP框架 - 创建实体

    用例演示 - 创建实体 本节将演示一些示例用例并讨论可选场景. 创建实体 从实体/聚合根类创建对象是实体生命周期的第一步.聚合/聚合根规则和最佳实践部分建议为Entity类创建一个主构造函数,以保证创 ...

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

    目录 系列文章 领域逻辑和应用逻辑 多应用层 示例:正确区分应用逻辑和领域逻辑 学习帮助 系列文章 基于ABP落地领域驱动设计-00.目录和前言 基于ABP落地领域驱动设计-01.全景图 基于ABP落 ...

  7. 【我们一起写框架】领域驱动设计的CodeFirst框架(一)—序篇

    前言 领域驱动设计,其实已经是一个很古老的概念了,但它的复杂度依旧让学习的人头疼不已. 互联网关于领域驱动的文章有很多,每一篇写的都很好,理解领域驱动设计的人都看的懂. 不过,这些文章对于那些初学者而 ...

  8. .net core +codefirst(.net core 基础入门,适合这方面的小白阅读) 【我们一起写框架】领域驱动设计的CodeFirst框架(一)—序篇

    .net core +codefirst(.net core 基础入门,适合这方面的小白阅读)   前言 .net core mvc和 .net mvc开发很相似,比如 视图-模型-控制器结构.所以. ...

  9. 基于ABP落地领域驱动设计-00.目录和小结

    <实现领域驱动设计> -- 基于 ABP Framework 实现领域驱动设计实用指南 翻译缘由 自 ABP vNext 1.0 开始学习和使用该框架,被其优雅的设计和实现吸引,适逢 AB ...

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

    目录 系列文章 数据传输对象 输入DTO最佳实践 不要在输入DTO中定义不使用的属性 不要重用输入DTO 输入DTO中验证逻辑 输出DTO最佳实践 对象映射 学习帮助 系列文章 基于ABP落地领域驱动 ...

随机推荐

  1. [LC735]行星碰撞

    题目描述 给定一个整数数组 asteroids,表示在同一行的行星.对于数组中的每一个元素,其绝对值表示行星的大小,正负表示行星的移动方向(正表示向右移动,负表示向左移动).每一颗行星以相同的速度移动 ...

  2. java第二章数组学习

    java第二章数组 数组的概念和特点 数组(Array),是多个相同类型数据按一定顺序排列的集合,并使用一个 名字命名,并通过编号的方式对这些数据进行统一管理. 特点 数组本身是引用数据类型,而数组中 ...

  3. runoob-TypeScript 教程

    https://www.runoob.com/typescript/ts-tutorial.html TypeScript 是 JavaScript 的一个超集,支持 ECMAScript 6 标准( ...

  4. TCP的“三次握手”和“四次挥手”

    转载:链接1 链接2 TCP connection 客户端与服务器之间数据的发送和返回的过程当中需要创建一个叫TCP connection的东西:由于TCP不存在连接的概念,只存在请求和响应,请求和响 ...

  5. Sybaris pg walkthrough Intermediate 从redis 到 rce

    nmap ┌──(root㉿kali)-[~/lab] └─# nmap -p- -A 192.168.166.93 Starting Nmap 7.94SVN ( https://nmap.org ...

  6. delphi中实现http请求和提交

    在对接本地的一个药械监管系统使用实现的代码,编译环境delphi Xe7 ,使用类TIdHTTP实现网络的get请求和post提交 //设置组件的属性 procedure TfrmMain.SetHt ...

  7. dart中Map类型详解

    Map是什么 map类型的数据都是由key和value两个值组成, key是唯一的,value不必唯一,读写数据都是通过key进行. key和value可以是任意类型数据. Map的基本使用 01== ...

  8. HTML标签-form表单

    HTML标签-form表单 在Web开发中,HTML表单(form)是不可或缺的一部分,它承担着用户与Web服务器之间交互的重任.今天,我们就来详细探讨一下HTML中的form表单标签. 一.form ...

  9. FreeSql学习笔记——6.修改

    前言   FreeSql 提供丰富的数据库更新功能,支持单条或批量更新,支持更新指定的字段,在特定的数据库执行还可以返回更新后的记录.与删除一样,没有条件的话不会执行,避免全表修改到全表:     指 ...

  10. C语言中函数有多个返回值的实现

    在C中,正常情况下,我们只能从函数中返回一个值.但在有些情况下,我们需要从函数中返回多个值,此时使用数组或指针能够很好地完成这样的任务.这里是一个示例,这个程序使用一个整型数组作为参数,并将数组元素的 ...