1

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

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

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

如果每个状态的表示完全相同,我将只使用原始属性并完成它。然而,由于不同的状态有略微不同的表示,我一直在努力找出最好的建模方法。管理内部状态的逻辑有点混乱,所以我想我会退后一步重新考虑。有什么想法吗?

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

4

5 回答 5

1

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

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

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

于 2010-01-25T18:05:40.017 回答
1

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

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

于 2010-01-25T21:00:21.663 回答
1

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

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?

其次,您是在与任务还是调度程序交互?给调度器一个任务描述并返回一个未来,这可以查询任务的结果,这并不少见。但任务本身并没有暴露,只有是否完成和结果。如果您需要进度,您可能需要一个可以通过任务 ID 查询以获取进度的调度程序,而不是您持有引用的任务对象 - 拥有一个同时更改状态的任务对象很难获得一致的集合状态数据,直到它达到最终状态。如果“通过”状态没有失败信息,那么查询“你失败了吗”,然后是“获取失败状态”很容易导致竞争,除非你将锁定外部化(ewww),

于 2010-01-25T21:44:13.543 回答
0

看看状态模式。

于 2010-01-25T17:51:37.277 回答
0

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

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()
      {
            ...
      }
      ...

}
于 2010-01-25T18:04:21.453 回答