Как провести рефакторинг нескольких сложных веток if-else - PullRequest
3 голосов
/ 03 июня 2011

Эта проблема относится к программному обеспечению, которое используется компаниями, которые организуют мероприятия. Когда активность изменяется (статус, время начала, количество человек), некоторые люди должны быть уведомлены об этом (по электронной почте). Код, отвечающий за это, начинался очень просто: тело письма содержало все старые значения и новые значения информации, которая была изменена.

За эти годы было введено много небольших правил. Например: если новый статус «отменен», темой письма должно быть: «Активность отменена» вместо «Активность изменена». Если предыдущий статус отсутствует (таким образом, действие является новым), а текущий статус является «окончательным», тогда тема должна быть «Новое действие на [дата]», а тело должно содержать полный обзор (поэтому никаких изменений).

Указанные выше правила служат только для иллюстрации проблемы. Их довольно много (относительно комбинаций статуса / даты / времени / и т. Д.), Всего до 500 строк кода.

Проблема заключается в том, что этот код в настоящее время довольно сложен для понимания и сопровождения. Время от времени вводятся новые правила, и добавление их без нарушения других правил может быть проблемой. Каков наилучший способ переписать подобный код в более понятный и поддерживаемый код? В настоящее время порядок ветвей if-else также очень важен. Первый оператор if является наиболее важным, следующий оператор else-if немного менее важен, до последнего предложения else для наиболее общего случая.

Ответы [ 2 ]

4 голосов
/ 03 июня 2011

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

Есть ли у вас интерфейс, представляющий правило?Что-то вроде

public class Activity {}

public interface Rule {
     boolean applies(Activity);

     Activity applyRule(Activity x);
}

Учитывая это, вы можете реализовать функцию сокращения, чтобы применять правила по порядку, пока не достигнете конца списка.

Activity applyRules(List<Rule> rules, Activity);
2 голосов
/ 03 июня 2011

Я бы разделил правила и их применение, чтобы ваш код стал

For all Rules
   if ThisRule.Applies(activity) then
       ThisRule.ApplyActions(email);
       break;

Тогда правила будут классом, в котором каждое правило имеет Applies и ApplyActions или ConstructEmail или что-то в этом роде.

Вы строите список правил в приоритетном порядке. Как только это будет сделано, вам нужно будет только перебрать список.

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

Сложность состоит в разделении различных правил, Например, если у вас есть правило, в котором новый статус отменяется, поэтому вы должны поместить отмененный в заголовок, но у вас есть другое правило, которое также применяется, тогда вам нужен механизм для применения нескольких правил, таких как:

For all Rules
   if ThisRule.Applies(activity) then
       ThisRule.ApplyActions(email);
       if ThisRule.TerminalRule then
           break;

так что простые правила, такие как изменение темы, позволяют применять и другие правила.

...