Как заставить сложные условия выглядеть красиво и сохранить количество утверждений?
В моем java-приложении у меня есть огромный набор условий, который решает только одно действие. Мой вопрос заключается в том, как сделать его красивым (я использую NetBeans, поэтому я бы предпочел решение, которое не будет нарушено его функцией форматирования кода). Я также хотел бы иметь там как можно меньше утверждений if/else, потому что я думаю, что это сделает его быстрее.
Мой исходный код был в беспорядке, поэтому я сделал диаграмму действий: . возьмите копию , Если хотите поиграть с ней. Пожалуйста, продолжайте имейте в виду, что схема не идеальна в отношении синтаксиса UML , отчасти потому, что я сделал это с помощью google docs.Это код:
if (!config.get("checkForSpecials") || event.isNotSpecial()) {
if (config.get("filterMode").equals("blacklist")) {
if (!itemFilter.contains(event.getItem().getName())) {
item.process();
}
} else if (config.get("filterMode").equals("whitelist")) {
if (itemFilter.contains(event.getItem().getName())) {
item.process();
}
} else {
item.process();
}
}
Есть две вещи, которые мне не нравятся в этом-условия не слишком ясны (особенно когда я разворачиваю полные имена методов и строки конфигурации), и тот факт, что вызов метода процесса происходит три раза.4 ответа:
Разложение логических элементов на множители и кэширование возвращаемых значений из вызовов методов может помочь уточнить код.
Кроме того, построение графиков всех результатов на логической таблице может помочь. Я использую Этот инструмент , чтобы помочь.
С помощью связанного инструмента:
A: config.get("filterMode").equals("blacklist") B: config.get("filterMode").equals("whitelist") C: filterContainsName (see below)
Инструмент штампует:
(!A && !B) || (!A && C) || (A && !C)
, что приводит к приведенному ниже коду (с небольшой настройкой, которая заменяет
(!A && C)
на(B && C)
):boolean filterContainsName = itemFilter.contains(event.getItem().getName()); boolean useBlacklist = config.get("filterMode").equals("blacklist"); boolean useWhitelist = config.get("filterMode").equals("whitelist"); if (!config.get("safeMode") || event.isSafe()) { if((!useBlackList && !useWhiteList) || ( useWhiteList && filterContainsName) || ( useBlackList && !filterContainsName)) { item.process(); } }
Используйте карты. Ключ карты-это условие / случай, значение-это единственный класс метода / интерфейс anonymouse, который содержит логику для этого условия. Всякий раз, когда вы сталкиваетесь с определенным условием/случаем, вы просто делаете поиск в карте и выполняете соответствующую функцию. Таким образом, вы даже можете разделить вашу логику по условию на отдельные классы (если это необходимо для красоты кода). В качестве дополнительного бонуса вы, вероятно, получите бонус за производительность, когда # условий > 10.
Выглядит хорошо, как мне кажется. Возможно, вы можете выделить допустимые условия для вызова метода
item.process()
, чтобы сделать его более понятным.if (!config.get("safeMode") || event.isSafe()) { if (isItemValidForProcess(config, itemFilter, event)) { item.process(); } } boolean isItemValidForProcess(config, itemFilter, event) { String filterMode = config.get("filterMode"); if (filterMode.equals("whitelist")) { return itemFilter.contains(event.getItem().getName()); } if (filterMode.equals("blacklist")) { return !itemFilter.contains(event.getItem().getName()); } return true; }
Хотите верьте, хотите нет, но схема не такая уж сложная.:) Здесь нет петли, и она довольно линейна.
Вот псевдокод, который реализует его
void action() if <sort out specials> if <is it special> return; if <check for unsafe items> if not <safe items list contains item> return; if <filter status = on> if < filter mode = whitelist> if not <item is on filter> return; else // black list if not <item is on filter> return; // finally! [process item]
Для действительно сложной диаграммы ответ таков ... Гото ...