Использовать свойства или методы для раскрытия бизнес-правил на С#?

Я пишу класс для инкапсуляции некоторых бизнес-правил, каждый из которых представлен логическим значением. Класс будет использоваться при обработке формы 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, на мой взгляд.