ООП дизайн: строка, перечисление, интерфейс или другое? - PullRequest
0 голосов
/ 28 октября 2009

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

Этот пример является произвольным, поэтому нет необходимости в конкретных советах, но, скажем, в базе данных есть таблица с именем "WorkflowStep", для которой я пишу класс. В таблице есть столбец с именем «CurrentStatus», который определяет, в каком состоянии находится рабочий процесс. Он хранится как varchar. Для этой колонки есть пять разных строк во всей таблице, и вряд ли они будут изменены ... значения, такие как "Open", "Closed", "On Hold" и т. Д.

Класс должен отслеживать это значение, но каким образом? Я мог бы пойти по простому пути и просто сохранить его в строке, но это не очень четко определено, и я бы предположил, что будущие разработчики будут искать разные значения строки для применения логики. Я мог бы пойти с перечислением, чтобы сделать вещи более четко определенными, но это могло привести к аду переключения / случая повсюду. Я читал подходы, в которых инженеры создают интерфейс, скажем «IStatus», а затем создают конкретные классы, которые представляют каждое возможное состояние статуса, но некоторые другие столбцы в той же ситуации, что и этот, могут иметь сто различных значений, поэтому 100 классы для каждого штата кажутся излишними.

Мой главный вопрос: является ли один подход де-факто лучше других, и если нет, что мне следует рассмотреть, чтобы выбрать подход?

Обратите внимание, что проект все еще находится в зачаточном состоянии, и я не уверен, как именно будет использоваться этот атрибут "status" класса. Это может быть даром, или это может оказаться жизненно важным: я еще не уверен.

Ответы [ 8 ]

2 голосов
/ 28 октября 2009

Я не думаю, что где-то есть однозначный ответ, но это общая проблема, и следующий подход всегда мне помогал:

  1. Если ваша бизнес-логика или какой-либо код никогда не будут ничего делать со значениями (сравнение, переключение на основе значения перечисления и т. Д.), Сохраните его в виде строки.
  2. Если вы будете сравнивать, используйте enum. Если у вас много таких таблиц или значения могут измениться, это отлично подходит для генерации кода.
  3. Если значения имеют дополнительные метаданные, которые имеют к ним отношение, создайте классы, содержащие эти метаданные, а также перечисление для создания соответствующего класса (в заводском методе). Опять же, генерация кода здесь отлично подходит.

Для чего-то вроде CurrentStatus это звучит так, как будто вариант 2 или 3 был бы естественным соответствием. Вариант 3 предпочтителен, если применима любая из следующих ситуаций:

  • Требуется «дружественное» имя для статуса с пробелами или не алфавитно-цифровыми символами (все, что не может обработать Enum.ToString ()).
  • Существует дополнительная логика или свойства, которые «приходят» с определенным статусом. Например, если у вас есть логика, при которой определенное действие может быть выполнено для элементов «OnHold» или «Закрыто», но не для элементов «Открыть», может иметь смысл иметь свойство «CanDoAction» для класса.
  • База данных, из которой вы извлекаете, имеет справочную таблицу для статусов с информацией, относящейся к тем статусам, которые вы, возможно, захотите использовать в своем коде.
2 голосов
/ 28 октября 2009

Лично я предпочитаю этот вид заявления о переключении

var x = new Dictionary<Status, Action>  
  {Status.Fail, ()=>Console.Writeline("Fail")}
  {Status.Ok, ()=>Console.Writeline("Ok")};  

x[Status.Fail]();
x[Status.Ok]();

Также - вам может понравиться эта статья Джимми (на случай, если вы будете придерживаться решения enum-fashioned).

1 голос
/ 28 октября 2009

Шаблон состояния звучит разумно.

В случае, если у вас будет больше различных значений, вы можете использовать одну из корневых реализаций и добавить несколько декоратор-модель .

1 голос
/ 28 октября 2009

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

private Dictionary<WorkflowStep, Action> _actions = 
  new Dictionary<WorkflowStep, Action>();

Затем назначьте его с помощью

_actions.Add(WorkflowStep.Open, OpenCommand);
_actions.Add(WorkflowStep.Closed, ClosedCommand);

У вас были бы простые методы, подобные этому:

private void OpenCommand()
{
  // Do something
}

private void ClosedCommand()
{
  // Do something.
}

Наконец, чтобы вызвать его, вы должны сделать:

if (_actions[step] != null)
{
  _actions[step]();
}

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

1 голос
/ 28 октября 2009

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

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

1 голос
/ 28 октября 2009

Это очень распространенная проблема, которая во многом зависит от понимания проблемы. Обычно я рассматриваю это как пересечение простоты, читабельности, расширяемости.

  1. Перечисление / Список констант . Это самый простой маршрут, и он хорошо читается, если вы будете работать с кодом гораздо больше, чем с необработанными данными. Расширяемость невелика, потому что вам нужно сделать рефакторинг, чтобы все было просто.
  2. Строки . Преимущество строк в том, что вы можете легко понять данные базы данных с первого взгляда. Тем не менее, они, как правило, добавляют к программе программный код, и они тоже не очень расширяемы.
  3. Справочная таблица . Это самый расширяемый из трех на сегодняшний день. Читаемость несколько снижена, потому что теперь вам нужно искать значения в справочной таблице всякий раз, когда вы хотите выяснить, что происходит. Кодирование для этого является самым сложным из трех.

Самое простое = Enum. Наиболее читаемый = Строки. Наиболее расширяемый = Справочная таблица.

Какой из них лучше всего подходит для вашей проблемы?

1 голос
/ 28 октября 2009

Я бы порекомендовал вам изучить концепцию «тип-значения», как это определено в домене. Эта штука WorkflowStep звучит как главный кандидат. Вы не упоминаете, на каком языке или в какой среде вы кодируете, но в .Net, если бы я использовал эту концепцию, я бы создал структуру, которая представляла бы этот объект и была закодирована так, чтобы в его публичном интерфейсе, используемом клиентский код во всей остальной системе, он выглядел как и будет использоваться как enum.

MyTask.WorkFlowStatus = WorkFlowStep.OnHold; 
// creates and assigns new instance of struct

In C #

  public struct WorkflowStep 
  {
     public static readonly WorkflowStep Null   = new WorkflowStep();
     public static readonly WorkflowStep Open   = new WorkflowStep(1);
     public static readonly WorkflowStep Closed = new WorkflowStep(2);
     public static readonly WorkflowStep OnHold = new WorkflowStep(3);
     private int val;
     private bool def;
     public bool HasValue { get { return def; } }
     public bool IsNull   { get { return !def ; } }
     private WorkflowStep ( ) { } // disable public instantiation
     private WorkflowStep (int value) 
     {
       val = value;
       def = true ;
     }
  }

Вы можете ввести свойства других предложений в вашей модели, которые должны отслеживать это как WorkflowStep. Объем памяти в памяти каждого экземпляра этой структуры очень мал, int для хранения значения и bool для хранения его обнуляемого статуса. Вы можете добавить дополнительные методы и перегрузки в структуру, чтобы включить выходные данные формата печати, перегрузки ToString, все, что вы хотите ...

1 голос
/ 28 октября 2009

Я прочитал подходы, в которых инженеры создают интерфейс, говорят «IStatus», а затем создают конкретные классы, которые представляют каждое возможное состояние статуса

Это будет шаблон состояния .

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

Это похоже на отдельную проблему. Там не так много, чтобы сказать об этом без более подробной информации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...