Как мне правильно моделировать с несколькими состояниями? - PullRequest
1 голос
/ 25 января 2010

У меня есть сущность, эквивалентная задаче, которая может иметь несколько состояний. «Задача» может находиться в состоянии ожидания, пройдена или не выполнена. Каждое из этих состояний также будет иметь некоторые уникальные данные. Например, в состоянии сбоя у объекта должна быть причина сбоя, в состоянии ожидания у него должен быть крайний срок для оценки и т. Д.

Хотя вышесказанное заставляет меня думать, что у меня должен быть отдельный объект для представления каждого состояния, базовый идентификатор объекта должен оставаться прежним, что подталкивает меня к мысли об этом как об одном объекте.

Кроме того, переход из состояния в состояние требует некоторой логики. «Ожидающая» задача, переходящая в «пройденное» состояние, будет обрабатываться иначе, чем «не выполненная» задача, выполняющая тот же переход.

Если бы представления для каждого состояния были в точности одинаковыми, я бы просто использовал примитивное свойство и покончил бы с ним. Однако, поскольку разные состояния имеют немного разные представления, я изо всех сил пытался найти лучший способ смоделировать это. Логика управления внутренним состоянием становится немного грязной, поэтому я решил отступить и пересмотреть. Есть мысли?

Я использую c #, хотя я считаю этот язык независимым.

Ответы [ 5 ]

1 голос
/ 26 января 2010

«Задача» может находиться в состоянии ожидания, пройдена или не выполнена. «Ожидающая» задача, переходящая в «пройденное» состояние, будет обрабатываться иначе, чем «невыполненная» задача, выполняющая тот же переход.

Это кажется довольно странным набором состояний. Я ожидал бы, что задача займет некоторое время для выполнения, поэтому переход от ожидающего к выполнению затем либо проходит, либо завершается неудачей, а задачи, которые не выполняются до истечения их времени, истекают. Если также существует переход от сбоя к отказу и истечению срока действия, то это может добавить другое состояние.

Нарисуйте конечный автомат, чтобы найти состояния.

Во-первых, нужно ли вам структурно моделировать состояния? Подойдут ли ожидающий / истекший флаг, запланированное время и результат (с неудачей и успехом как два подтипа результата)? Что от этого нужно клиентам задачи?

Во-вторых, вы взаимодействуете с задачей или планировщиком? Весьма обычно дать описание задачи планировщику и вернуть будущее, которое можно спросить о результате задачи. Но сама задача не выставляется, только завершена ли она и результат. Если вам требуется прогресс, вам может потребоваться иметь планировщик, который можно запрашивать по идентификатору задачи, чтобы получить прогресс, а не объект задачи, на который вы ссылаетесь - наличие объекта задачи, который одновременно изменяет состояние, затрудняет получение согласованного набора данных о состоянии от него, пока он не достигнет конечного состояния. Если в «пройденном» состоянии нет информации о сбое, то запрос «есть ли у вас сбой», за которым следует «получить статус сбоя», легко приводит к гонке, если только вы не извлекаете блокировку (ewww), поэтому возвращение объекта информации о состоянии неизменной задачи атомарно становится желательно, когда ваш объект задачи становится более или менее эквивалентным идентификатору, переданному планировщику.

1 голос
/ 26 января 2010

Использование чисто объектно-ориентированного подхода имеет свои недостатки.Если вы не планируете выполнять много полиморфного управления кодом, избегайте непосредственного представления состояния класса вашего домена с помощью полиморфизма.Я остановился на более гибридном подходе.Различные состояния должны быть смоделированы как отдельное дерево наследования родительских / дочерних объектов.Начните с абстрактного базового класса MyState, у которого в качестве дочерних элементов MyState1, MyState2 и MyState3.(см. ответ Джеффри для примера.

Сущность, для которой требуется отслеживание состояния, имеет атрибут «current-state», который имеет тип MyState. Когда сущность изменяет состояние, этопростой присваивание или вызов setter () для его изменения. При желании вы можете создавать единичные экземпляры каждого состояния или создавать новые экземпляры для каждого изменения состояния. Это зависит от того, как часто изменяется состояние и сколько объектов отслеживают свое состояние.Если числа становятся слишком большими, вы можете рассмотреть синглтонный подход.

1 голос
/ 25 января 2010

Когда я впервые прочитал этот вопрос, мой ответ состоял в том, чтобы использовать перечисление для определения состояния.Однако, перечитав его, я бы предложил одно из следующего:

  1. Реализовать каждую задачу как отдельный класс (PendingTask, PassedTask, ...) с тем же родителем и конструктором, который принимаетзадача любого типа, которая предшествует этому состоянию.
  2. Реализуйте одну задачу и создайте новый класс TaskStateData с дочерними классами для данных, необходимых для каждого состояния.
  3. Реализуйте одну задачу, но у вас естьотдельный метод для изменения состояния для каждого типа состояния с параметрами для дополнительных атрибутов, необходимых для этого состояния

Я предлагаю эти решения для обеспечения целостности данных.

0 голосов
/ 25 января 2010

Это звучит как идеальное применение наследования объектов и полиморфизма.

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

}
0 голосов
/ 25 января 2010

Посмотрите на шаблон состояния .

...