Использовать свойства или методы для раскрытия бизнес-правил на С#?
Я пишу класс для инкапсуляции некоторых бизнес-правил, каждый из которых представлен логическим значением. Класс будет использоваться при обработке формы InfoPath, поэтому правила получат текущее состояние программы, просматривая значения в глобальной структуре данных XML, используя операции XPath. Какой лучший (самый идиоматический) способ разоблачить эти правила для вызывающих - свойства или общедоступные методы?
Вызов с использованием свойств
Rules rules = new Rules();
if ( rules.ProjectRequiresApproval ) {
// get approval
} else {
// skip approval
}
Вызов с использованием методов
Rules rules = new Rules();
if ( rules.ProjectRequiresApproval() ) {
// get approval
} else {
// skip approval
}
Правила, описывающие правила класса как свойства
public class Rules() {
private int _amount;
private int threshold = 100;
public Rules() {
_amount = someExpensiveXpathOperation;
}
// rule property
public bool ProjectRequiresApproval {
get { return _amount > threshold }
}
}
Правила размещения правил класса как методы
public class Rules() {
private int _amount;
private int threshold = 100;
public Rules() {
_amount = someExpensiveXpathOperation;
}
// rule method
public bool ProjectRequiresApproval() {
return _amount > threshold;
}
}
Каковы плюсы и минусы одного над другим?
Ответы
Ответ 1
Все это сводится к передаче семантики тому, кто потребляет эту бизнес-логику.
Свойство является внутренним значением определенного объекта. Rules
в вашем примере - механизм бизнес-логики, поэтому любые свойства, которые он предоставляет, должны применяться к состоянию и поведению этого движка, а не к данным, которые были обработаны им. Таким образом, ProjectRequiresApproval()
- это действие, которое движок применяет к внешнему объекту.
Если, с другой стороны, существует метод Rules.GetProcess()
, который возвращает объект Process
, RequiresAproval
может быть свойством для этого объекта.
Ответ 2
Во-первых, вам нужно обернуть get {} вокруг логики свойств, и эмпирическое правило (для меня, во всяком случае) должно заключаться в том, что метод может изменять содержимое класса или выполнять какую-либо бизнес-логику, тогда как свойство предоставляет информацию о классе.
Для вашего использования я бы предложил свойство, поскольку значения уже существуют, и вы создаете то, что известно как производное свойство.
Кроме того, ваш код может быть реорганизован на
return _amount < threshold;
Ответ 3
В соответствии с "Свойства против методов" в MSDN (по общему признанию, для более старой версии Visual Studio) это звучит так, как если бы методы более подходящим, чем свойства в вашем случае (при условии, что правила становятся более сложными, чем пороговые значения).
Немного больше по этому поводу выяснилось следующее:
- отличный ответ от Кена Браунинга о свойствах и методах вообще
- A сообщение в блоге от Билла Вагнера (автор Effective С#) о том, какие условия должны быть истинными, чтобы использовать свойство
- Ссылки на пару движков с открытым исходным кодом (NxBRE и Drools.NET), чтобы вы могли видеть альтернативы для реализации бизнес-правил.
Ответ 4
Я согласен с Энтони Кохом. Я использую методы, когда мне нужно выполнить сложный расчет, который изменяет состояние класса. Если для текущего состояния класса, в котором данные уже существуют в этом состоянии и не нуждается в изменении, требуется простой расчет или извлечение данных, свойство кажется более подходящим.
Ответ 5
Это настоящий пример? Я спрашиваю, потому что я нахожу это странным, что объект Rules может иметь сумму и порог. Я упоминаю об этом, потому что думаю, что это часть ответа. Я бы предположил, что ваши Правила должны быть пространством имен, а Project - объектом, и независимо от того, требует ли оно утверждение, было бы свойством класса Project, на мой взгляд.