领域驱动设计 - 我发现很难为这种业务逻辑提出解决方案

发布于 2025-01-05 15:44:19 字数 2361 浏览 0 评论 0原文

简介

假设我有三个领域对象:

Proposition
Phase
Task

一个命题可以有一个或多个阶段。一个阶段可以有一个或多个任务。

如果我完成了最后一个阶段的最后一个任务,则该提案必须设置为“已关闭”。

在代码中,我创建了类似的东西来完成阶段

//My Business Layer does this:
--------------------------------------
pseudo:
var phase = _phaseRepository.GetById(id);
phase.LastTask.SetComplete();


// My Domain Entities look like this:
------------------------
public class phase()
{
   public Task LastTask { get; set; } // not real code of course
}

public class Task()
{
   public Phase Phase { get; set; }

   public void SetComplete()
   {
      Phase.IsFinished = true;
   }
}

问题

的最后一个任务我在哪里放置代码以将提案设置为“已关闭”?

选项

我认为有几个选项:

1)在域实体中:Task.SetComplete

public class Task()
{
   public Phase Phase { get; set; }

   public void SetComplete()
   {
      Phase.IsFinished = true;
      Phase.Proposition.IsClosed = true;
   }
}

2a)在业务层中

var phase = _phaseRepository.GetById(id);
phase.LastTask.SetComplete();

var proposition = _propositionRepository.GetById(phase.PropositionId);
proposition.IsClosed = true;

2b)在业务层中,也许更好一点的方式:

var phase = _phaseRepository.GetByIdIncludingProposition(id);
phase.LastTask.SetComplete();
phase.proposition.SetClosed();

3)让一切都通过命题:

//My Business Layer:
var proposition = _propositionRepository.GetById(id);
proposition.CompleteTask(taskId);

// Domain Object:
public class Proposition()
{
   public List<Phase> Phases { get; set; }

   public void CompleteTask(long taskId)
   {
      var task = // psuedo: select relevant task from Phases.Tasks, using taskid
      task.SetComplete();
      task.Phase.SetFinished();

      //psuedo: if task.Phase is last phase in proposition
      Phase.Proposition.IsClosed = true;
   }
}

关于选项

选项 1 是有问题的,

Phase.Proposition.IsClosed = true;

因为 Proposition 不需要加载,如果它没有加载,我们会得到一个异常。

选项 2a 是有问题的,因为在执行 Phase.LastTask.SetComplete() 后,命题未处于正确的状态。在任何可以访问 Phase 的代码中,都可以执行“phase.LastTask.SetComplete()”,而无需对 Proposition 执行相关操作。

选项 2b 与 2a 存在相同的问题。

选项 3 赋予 Proposition 类太多的责任。

你们有什么建议吗?

Introduction

Let's say I have three Domain Objects:

Proposition
Phase
Task

A Proposition can have one or more Phases. A Phases can have one or more Tasks.

If I completed the last Task in the last Phase, the Proposition must be set to 'Closed'.

In code I've created something like this to complete the last Task of a Phase

//My Business Layer does this:
--------------------------------------
pseudo:
var phase = _phaseRepository.GetById(id);
phase.LastTask.SetComplete();


// My Domain Entities look like this:
------------------------
public class phase()
{
   public Task LastTask { get; set; } // not real code of course
}

public class Task()
{
   public Phase Phase { get; set; }

   public void SetComplete()
   {
      Phase.IsFinished = true;
   }
}

Question

Where do I put the code to set the Proposition to 'Closed'?

Options

I think have a few options:

1) In the Domain Entity: Task.SetComplete

public class Task()
{
   public Phase Phase { get; set; }

   public void SetComplete()
   {
      Phase.IsFinished = true;
      Phase.Proposition.IsClosed = true;
   }
}

2a) In the Business Layer

var phase = _phaseRepository.GetById(id);
phase.LastTask.SetComplete();

var proposition = _propositionRepository.GetById(phase.PropositionId);
proposition.IsClosed = true;

2b) In the Business Layer, maybe a bit nicer way:

var phase = _phaseRepository.GetByIdIncludingProposition(id);
phase.LastTask.SetComplete();
phase.proposition.SetClosed();

3) Let everything pass thru Proposition:

//My Business Layer:
var proposition = _propositionRepository.GetById(id);
proposition.CompleteTask(taskId);

// Domain Object:
public class Proposition()
{
   public List<Phase> Phases { get; set; }

   public void CompleteTask(long taskId)
   {
      var task = // psuedo: select relevant task from Phases.Tasks, using taskid
      task.SetComplete();
      task.Phase.SetFinished();

      //psuedo: if task.Phase is last phase in proposition
      Phase.Proposition.IsClosed = true;
   }
}

About the options

Option 1 is problematic on the line

Phase.Proposition.IsClosed = true;

because Proposition doesn't have to be loaded, and if it's not loaded we get an exception.

Option 2a is problematic because after phase.LastTask.SetComplete() is executed the proposition is not in the correct state. And everywhere in code where one has access to Phase, "phase.LastTask.SetComplete()" can be executed without doing the relevant operations on Proposition.

Option 2b has the same problem as 2a.

Option 3 gives the Proposition class too much responsibilities.

Do you guys have any suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

猫烠⑼条掵仅有一顆心 2025-01-12 15:44:19

我猜测命题是聚合根。任务最终是命题的一部分,我认为 Tssk 应该通知已完成我会尝试这种方法(基本上选项 3 稍作修改)

public class Proposition()
{
  public Task GetTask(int taskId)
  {
      //find and return task
  } 
}

//in business layer 
var p= _repository.GetProposition(id);
p.GetTask(taskId).SetComplete();

public class Task
{
  public event Action<Task> Completed;       


   public void SetComplete()
   {
        if (Completed!=null) Completed(this);
    }

阶段应该处理Task 的完成事件,触发时检查是否是最后一个任务,并通知 Proprisiton 关闭。现在,也许使用事件并不是最好的实现,可能观察者模式更好,但主要思想是:

  • 通过 Proposition 方法获取任务(因为 Proposition 是 AR)
  • 任务完成时通知阶段 阶段
  • 在最后一个阶段通知命题任务已完成
  • 提案应检查是否没有任何正在进行的阶段并自行关闭。
  • 在存储库中保存命题

想想看,这基本上是领域事件模式。

I'm guessing that Proposition is the aggregate root.A task is part of a proposition in the end and I think that the Tssk should notify that is completed i'd try this approach (basically option 3 a bit modified)

public class Proposition()
{
  public Task GetTask(int taskId)
  {
      //find and return task
  } 
}

//in business layer 
var p= _repository.GetProposition(id);
p.GetTask(taskId).SetComplete();

public class Task
{
  public event Action<Task> Completed;       


   public void SetComplete()
   {
        if (Completed!=null) Completed(this);
    }

The Phase should handle the completed event of Task and when it is triggerd, chek if it's the last task and notify the proporisiton to closeitself. NOw maybe using events is not the best implemetnation, probably the Observer pattern is better, but the main ideas are:

  • You get a task via a Proposition method (as Proposition is an AR)
  • Tasks notifies phase when it's finished
  • Phase notifies proposition when the last task is completed
  • Proposition should check if there aren't any phases in progress and close itself.
  • save Proposition in the repository

Come to think of it, this is basically the domain event pattern.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文