Как заставить сложные условия выглядеть красиво и сохранить количество утверждений?


В моем 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 7

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]

Для действительно сложной диаграммы ответ таков ... Гото ...