我应该如何为具有多个状态的实体建模?

发布于 2024-08-19 06:49:46 字数 393 浏览 10 评论 0原文

我有一个实体,相当于一个任务,可以有多个状态。 “任务”可以处于挂起、通过或失败状态。这些状态中的每一个也将有一些独特的数据。例如,在失败状态下,实体应该有失败的原因,在待定状态下,它应该有评估的最后期限,等等。

虽然上述内容使我认为我应该有一个单独的对象来代表每个状态, 但实体的底层 ID 应保持不变,这让我重新将其视为单个对象。

此外,从一个状态转换到另一个状态需要一些逻辑。转换到“通过”状态的“待处理”任务将与进行相同转换的“失败”任务区别对待。

如果每个状态的表示完全相同,我只需使用原始属性即可完成。然而,由于不同的州有稍微不同的表示,我一直在努力找出建模的最佳方法。管理内部状态的逻辑变得有点混乱,所以我想我应该退一步重新考虑。有什么想法吗?

我正在使用 c#,尽管我认为这种语言是不可知的。

I have an entity, equivalent to a task, that can have multiple states. The "task" can either be in a pending, passed, or failed state. Each one of these states will also have some unique data. For instance, in a failed state the entity should have a reason for the failure, in the pending state it should have a deadline for evaluation, etc.

While the above leads me to think I should have a separate object to represent each state, the underlying ID for the entity should remain the same, pushing me back towards thinking of this as a single object.

Also, transitioning from state to state requires some logic. A "pending" task transitioning to a "passed" state will be treated differently than a "failed" task making the same transition.

If the representations for each state were exactly the same I'd just use a primitive property and be done with it. However, since the different states have slightly different representations, I've been struggling to figure out the best way to model this. The logic for governing the internal state is getting a little messy so I figured I'd step back and reconsider. Any thoughts?

I'm using c# though I'd consider this language agnostic.

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

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

发布评论

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

评论(5

不及他 2024-08-26 06:49:46

当我第一次读到这个问题时,我的答案是使用枚举来定义状态。不过,在重读之后,我建议采用以下方法之一:

  1. 将每个任务实现为具有相同父级的单独类(PendingTask、PassedTask...),以及接受该状态之前出现的任何类型任务的构造函数。
  2. 实现一个任务,并创建一个新类 TaskStateData,其中包含每个状态所需数据的子类。
  3. 实现一个任务,但有一个单独的方法来更改每种状态类型的状态,并带有该状态所需的额外属性的参数,

我建议使用这些解决方案来确保数据完整性。

When I first read this question, my answer was to use an enumeration to define the state. After rereading it, though, I would suggest one of the following:

  1. Implement each task as a separate class (PendingTask, PassedTask,...) with the same parent, and a constructor that accepts a task of any type that comes before that state.
  2. Implement one Task, and create a new class TaskStateData with child classes for the data needed for each state.
  3. Implement one Task, but have a separate method to change the state for each state type with parameters for the extra attributes needed for that state

I suggest these solutions to ensure data integrity.

毁虫ゝ 2024-08-26 06:49:46

采用纯粹的面向对象方法有其缺点。除非您计划必须进行大量多态代码管理,否则请避免直接使用多态性来表示域类的状态。我决定采用一种更加混合的方法。不同的状态需要建模为单独的父/子继承树。从抽象基类 MyState 开始,它有子类 MyState1、MyState2 和 MyState3。 (请参阅 Jeffrey 的回答了解例如,

需要跟踪其状态的实体具有 MyState 类型的属性,当实体更改状态时,可以通过简单的赋值或 setter() 调用来更改它。状态(如果需要),或为每个状态更改构造新实例,这取决于状态更改的频率以及跟踪其状态的对象数量,如果数字太大,您可以考虑单例方法。

Going with a pure Object-Oriented approach has downsides. Unless you plan on having to do a lot of polymophic code managing, avoid representing your domain class's state using polymorphism directly. I've settled on a more hybrid approach. The different states need to be modeled as a separate parent/child inheritance tree. Start with an abstract base class MyState which have as children MyState1, MyState2, and MyState3. ( see Jeffrey's answer for an example.

The entity which needs its state tracked has an attribute of 'current-state' which is of type MyState. when the entity changes state it is a simple assignment or setter() call to change it. You can construct singleton instances of each state if so desired, or construct new instances for each state change. It depends on how often the state changes and how many objects are having their state tracked. If the numbers get too big you can consider the singleton approach.

神经大条 2024-08-26 06:49:46

“任务”可以处于挂起、通过或失败状态。
转换为“通过”状态的“待处理”任务将与进行相同转换的“失败”任务区别对待。

这似乎是一个相当奇怪的状态集合。我预计任务需要一些时间来执行,因此从待处理过渡到执行,然后通过或失败,并且在时间耗尽之前不执行的任务将过期。如果还存在从失败到失败并过期的转换,则可能会添加另一个状态。

画一个状态机来查找状态。

首先,您需要对状态进行结构建模吗?待定/过期标志、预定时间和结果会起作用吗(失败和成功作为结果的两个子类型)?任务的客户需要从中得到什么?

其次,您正在与任务或调度程序交互吗?向调度程序提供任务描述并返回可以查询任务结果的 future 的情况并不少见。但任务本身并不暴露,只暴露是否完成和结果。如果您需要进度,您可能需要一个可以通过任务 ID 查询以获取进度的调度程序,而不是您持有引用的任务对象 - 拥有同时更改状态的任务对象使得很难获得一致的集合的状态数据,直到达到最终状态。如果“通过”状态没有失败信息,那么查询“你失败了吗”,然后“获取失败状态”很容易导致竞争,除非您外部化锁定(ewww),因此原子地返回一个不可变的任务状态信息对象变成理想的,此时您的任务对象或多或少相当于传递给调度程序的 ID。

The "task" can either be in a pending, passed, or failed state.
A "pending" task transitioning to a "passed" state will be treated differently than a "failed" task making the same transition.

That seems a rather odd collection of states. I'd expect a task to take some time to execute, so transition from pending to executing then either pass or fail, and tasks which don't execute before their time runs out to expire. If there is also a transition from failed to failed-and-expired then that might add another state.

Draw a state machine to find the states.

Firstly, do you need to model the states structurally? Would a pending/expired flag, a scheduled time and a result do (with failure and success as the two sub-types of result)? What do clients of the task need from it?

Secondly, are you interacting with a task or a scheduler? It is not uncommon to give a task description to a scheduler and to get back a future, which can be queried about the result of the task. But the task itself is not exposed, only whether it is complete and the result. If you require progress, you might want to have a scheduler which can be queried by task ID to get progress, rather than a task object you hold a reference to - having a task object which changes state concurrently makes it hard to get a consistent set of state data from it, until it reaches a final state. If the 'passed' state does not have failure information, then querying 'are you failed', followed by 'get failure status' easily leads to a race unless you externalise locking (ewww), so returning an immutable task state information object atomically becomes desirable, by which time your task object becomes more or less equivalent to the ID passed to a scheduler.

何时共饮酒 2024-08-26 06:49:46

这听起来像是对象继承和多态性的理想应用。

abstract class Task
{
      public int TaskId { get; private set; }
      abstract PassedTask TransitionToPassed();
      ...
}

class PendingTask : Task
{
      PassedTask TransitionToPassed()
      {
            PassedTask passed = new PassedTask();
            passed.TaskId = TaskId;
            ...
            return passed;
      }
      ...
}

class PassedTask : Task
{
      PassedTask TransitionToPassed()
      {
            return this;
      }
      ...
}

class FailedTask : Task
{
      public string ReasonForFailure { get; private set; }
      PassedTask TransitionToPassed()
      {
            ...
      }
      ...

}

This sounds like an ideal application of object inheritance and polymorphism.

abstract class Task
{
      public int TaskId { get; private set; }
      abstract PassedTask TransitionToPassed();
      ...
}

class PendingTask : Task
{
      PassedTask TransitionToPassed()
      {
            PassedTask passed = new PassedTask();
            passed.TaskId = TaskId;
            ...
            return passed;
      }
      ...
}

class PassedTask : Task
{
      PassedTask TransitionToPassed()
      {
            return this;
      }
      ...
}

class FailedTask : Task
{
      public string ReasonForFailure { get; private set; }
      PassedTask TransitionToPassed()
      {
            ...
      }
      ...

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