2013-02-24 3 views
2

Я пытаюсь подключить летнее приложение MS Access с кодом VBA спагетти на C# и OOP, и я изо всех сил стараюсь найти лучший способ разместить логику домена в своих классах доменов.Как выразить логику домена в классе домена?

Я буду использовать класс Country в качестве простого примера. Он имеет три свойства с различными бизнес-правилами:

  • CountryCode не может больше быть изменен после того, как страна будет создана, потому что может вызвать проблемы с приложением 3 партии, которая использует страну
  • CountryName может быть изменен в любое время , без какого-либо базового логического или бизнес-правил
  • IsoCode может быть изменен в любое время, но должен быть ровно 2 символов
    (IsoCode имеют на самом деле больше правил, но в этом примере давайте предположим, что «должен быть ровно 2 символом» является единственный правило, для простоты)

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

  • делает это независимо от того, какой подход использовать?
  • У одного из них (или обоих) есть проблемы, которые я не вижу?
  • Есть ли другой способ, который еще лучше?

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


Версия 1:

public class Country1 
{ 
    public string CountryCode { get; private set; } 
    public string CountryName { get; set; } 
    public string IsoCode { get; private set; } 

    public Country1(string countryCode, string countryName, string isoCode) 
    { 
     this.CountryCode = countryCode; 
     this.CountryName = countryName; 
     SetIsoCode(isoCode); 
    } 

    public void SetIsoCode(string isoCode) 
    { 
     if (isoCode.Length != 2) 
     { 
      throw new ArgumentException("must be exactly 2 characters!"); 
     } 

     this.IsoCode = isoCode; 
    } 
} 

Версия 2:

public class Country2 
{ 
    public Country2(string countryCode, string countryName, string isoCode) 
    { 
     this.countrycode = countryCode; 
     this.CountryName = countryName; 
     this.isocode = isoCode; 
    } 

    private readonly string countrycode; 
    private string isocode; 

    public string CountryCode 
    { 
     get { return this.countrycode; } 
    } 

    public string CountryName { get; set; } 

    public string IsoCode 
    { 
     get { return this.isocode; } 
     set 
     { 
      if (value.Length != 2) 
      { 
       throw new ArgumentException("must be exactly 2 characters!"); 
      } 

      this.isocode = value; 
     } 
    } 
} 

Некоторые больше о том, почему фон Я спрашиваю об этом и о том, что я хочу знать:

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

Некоторые говорят, что вместо использования каких-либо геттеров и сеттеров вы должны использовать методы GetXXX и SetXXX. Я вижу, что это имеет смысл в некоторых случаях (например, метод SetXXX с несколькими параметрами, когда у вас есть несколько значений, которые необходимо установить вместе).
Но часто в моем примере есть простые значения, такие как CountryName, что является «немым» значением без какой-либо логики.Когда у меня есть десять из этих вещей в одном классе, я не хочу создавать методы GetXXX и SetXXX для каждого из них.

Тогда есть такие вещи, как IsoCode, который не имеет никакого отношения ни к каким другим свойствам (так что не нужно использовать метод SetXXX, чтобы установить его вместе с другим свойством). Но он содержит некоторую проверку, поэтому я мог либо сделать метод SetXXX, либо просто выполнить проверку (и выбросить исключение, если что-то не так) в установщике.

Вызывает ли исключение даже лучший способ уведомить вызывающего абонента об ошибке? Some say it's fine, и some say that you should throw exceptions only for "exceptional" cases.
IMO это действительно не исключительный случай, когда кто-то вводит недопустимый ISO-код, но как еще я могу получить информацию о том, что сообщение об ошибке (включая сообщение с возможностью чтения человеком!) Было передано клиенту? Лучше ли использовать объект ответа с кодом ошибки и свойство строки ErrorMessage?

ответ

1

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

SetXXX методы для всего - это обычное соглашение «Javaish» (по сравнению с его использованием на многих языках, у которых нет сеттеров и геттеров, таких как C#).

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

Старайтесь не быть маньяком ООП. Это только причинит вам боль в голове. ООП - это не религия (и даже религия не должна иметь фанатиков ИМХО, но это еще одна история).

Назад к точке

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

Validation

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

См. Ответ @Andy Skirrows для ссылок.

2

Лично я не думаю, что существует большая разница между реализацией свойства и метода. Я предпочитаю использовать свойства, когда значения могут быть установлены независимо. Я использую методы setter, чтобы заставить больше одной ценности быть предоставленной вашей модели одновременно, когда значения зависят друг от друга каким-либо образом (например, вы устанавливаете целые числа x и y и y не может быть больше x).

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

Я настоятельно рекомендую эту статью Эрик Липперт о том, какие условия делает хороший кандидат для метания/ловли исключение:

http://blogs.msdn.com/b/ericlippert/archive/2008/09/10/vexing-exceptions.aspx

+0

Что касается валидации: прямо сейчас у меня даже нет модели просмотра (как я уже говорил в начале моего вопроса: код спама доступа/VBA). Интерфейс, скорее всего, будет Winforms или WPF (еще не решен), но в любом случае: наличие логики проверки в модели представления хорошо, но наличие в классах доменов более важно IMO. Есть ли у вас хороший пример того, как я могу повторно использовать логику проверки в классах домена ** и ** в режиме просмотра? –

+0

_ У вас есть хороший пример того, как я могу повторно использовать логику валидации в классах домена и в viewmodel? _ Что происходит, когда вы этого не делаете: Новое требование: «Отобразить значение X на этом экране. " Нет проблем. У нас был класс домена А, который был классом для этого экрана. Класс домена B уже выполнил комплексный расчет для X, отображая его на другом экране. Таким образом, все, что нужно было сделать в A, было инстанцировать B и вызвать метод расчета. Ну, вы даже не могли создать экземпляр B, потому что он был так тесно связан с его webForm/экраном и несколькими другими классами. Потребовалось 3 месяца, чтобы исправить это. – radarbob

Смежные вопросы