如何控制业务流程?

时间:2023-01-26 18:09:01

如何控制业务流程?

上一篇:《DDD 领域驱动设计-如何完善 Domain Model(领域模型)?

开源地址:https://github.com/yuezhongxin/CNBlogs.Apply.Sample(代码已更新)

需要注意的是,业务流程并不是工作流程,在领域模型中,业务流程的控制很重要,在上篇的领域模型中我们就忽略了这一点,所以在后面的实现中,出现了一些严重的问题,主要是管理员审核 JS 权限申请的业务流程

先看一下 JsPermissionApply 实体中的 Pass 操作代码:

public async Task Pass() { this.Status = Status.Pass; this.ApprovedTime = DateTime.Now; this.ReplyContent = "恭喜您!您的JS权限申请已通过审批。"; eventBus = IocContainer.Default.Resolve<IEventBus>(); await eventBus.Publish(new JsPermissionOpenedEvent() { UserId = this.UserId }); await eventBus.Publish(new MessageSentEvent() { Title = "您的JS权限申请已批准", Content = this.ReplyContent, RecipientId = this.UserId }); }

对应的单元测试代码:

[Fact]
public async Task ProcessApply_WithPassTest() { var userId = 1; var jsPermissionApply = await _jsPermissionApplyRepository.GetWaiting(userId).FirstOrDefaultAsync(); Assert.NotNull(jsPermissionApply); await jsPermissionApply.Pass(); _unitOfWork.RegisterDirty(jsPermissionApply); Assert.True(await _unitOfWork.CommitAsync()); }

有没有发现一些问题?开通 JS 权限和消息通知,发生在 JsPermissionApply 实体对象持久化之前,这本身的设计就有问题,另外,如果 JsPermissionApply 实体对象持久化失败的话,开通 JS 权限和消息通知会正常执行,相反,开通 JS 权限和消息通知如果出现问题,JsPermissionApply 实体对象持久化也会不受影响,还有就是开通 JS 权限和消息通知放在一起也会有问题。

造成上面这些问题的原因,就是我们之前画的业务流程图太敷衍了,没有具体的进行细化设计,针对管理员审核 JS 权限申请的业务流程,我们再详细的画一下:

如何控制业务流程?

可以看到,管理员审核通过 JS 权限申请,JS 权限申请的状态改为“通过”,再开通 JS 权限,然后持久化 JS 权限申请,最后再消息通知用户,整个 JS 权限申请通过的业务流程顺序应该是这样的,对照上面这张图,再看之前的实现,确实牛头不对马尾。

简单总结下审核通过 JS 权限申请的业务流程顺序:

  1. JS 权限申请状态改为“通过”。
  2. 开通 JS 权限。
  3. 消息通知用户。

好,来看一下改进后的 JsPermissionApply 实体代码:

namespace CNBlogs.Apply.Domain { public class JsPermissionApply : IAggregateRoot { private IEventBus eventBus; public JsPermissionApply() { } public JsPermissionApply(string reason, int userId, string ip) { if (string.IsNullOrEmpty(reason)) { throw new ArgumentException("申请内容不能为空"); } if (reason.Length > 3000) { throw new ArgumentException("申请内容超出最大长度"); } if (userId == 0) { throw new ArgumentException("用户Id为0"); } this.Reason = reason; this.UserId = userId; this.Ip = ip; this.Status = Status.Wait; } public int Id { get; private set; } public string Reason { get; private set; } public int UserId { get; private set; } public Status Status { get; private set; } = Status.Wait; public string Ip { get; private set; } public DateTime ApplyTime { get; private set; } = DateTime.Now; public string ReplyContent { get; private set; } public DateTime? ApprovedTime { get; private set; } public bool IsActive { get; private set; } = true; public async Task<bool> Pass() { if (this.Status != Status.Wait) { return false; } this.Status = Status.Pass; this.ApprovedTime = DateTime.Now; this.ReplyContent = "恭喜您!您的JS权限申请已通过审批。"; eventBus = IocContainer.Default.Resolve<IEventBus>(); await eventBus.Publish(new JsPermissionOpenedEvent() { UserId = this.UserId }); return true; } public bool Deny(