Я пытаюсь подключить летнее приложение 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
?
Что касается валидации: прямо сейчас у меня даже нет модели просмотра (как я уже говорил в начале моего вопроса: код спама доступа/VBA). Интерфейс, скорее всего, будет Winforms или WPF (еще не решен), но в любом случае: наличие логики проверки в модели представления хорошо, но наличие в классах доменов более важно IMO. Есть ли у вас хороший пример того, как я могу повторно использовать логику проверки в классах домена ** и ** в режиме просмотра? –
_ У вас есть хороший пример того, как я могу повторно использовать логику валидации в классах домена и в viewmodel? _ Что происходит, когда вы этого не делаете: Новое требование: «Отобразить значение X на этом экране. " Нет проблем. У нас был класс домена А, который был классом для этого экрана. Класс домена B уже выполнил комплексный расчет для X, отображая его на другом экране. Таким образом, все, что нужно было сделать в A, было инстанцировать B и вызвать метод расчета. Ну, вы даже не могли создать экземпляр B, потому что он был так тесно связан с его webForm/экраном и несколькими другими классами. Потребовалось 3 месяца, чтобы исправить это. – radarbob