@jejos

Как избавиться от множества if?

У меня есть задача, которую я решил, однако, не уверен что моё решение можно назвать хорошим. Суть такова:
есть 3 числовых переменных A, B, C. Каждая из них содержит число, они могут быть как равны между собой в разный момент времени, так и не равны друг другу. Также, в 1-й или более переменных значение может отсутствовать (null). Условия задачи выглядят так: "если A > B > C, то ответ считать по формуле A + B + C", или "если ((A == null) && (C > B), то ответ считать по другой формуле (B / C) * 2" и таких условий несколько штук. Я так и закодировал, и мое решение выглядит как несколько подряд идущих if'ов (10 штук), и внутри каждого if'а расписано по какой формуле считать ответ. Но честно говоря, оно мне не нравится. Мне оно видится как куча if'ов, составляющих громоздкую конструкцию, но я не вижу, как можно сделать это более читаемым и понятным. Не понимаю, как обернуть эти условия в понятные абстракции с названиями, чтобы это перестало быть похожим на кучу математических формул. Как можно сделать лучше?
Пример кода, о котором я говорю (и таких if 10 штук подряд):

if ((A < B) && (C > B)) {
value = (A + B) - 1
}
if ((A == null) && (C < B)) {
value = (C + B) * 2
}

PS: лучшее, что я пока смог придумать, это обернуть все эти вычисления в функцию, и дать поясняющие комментарии.
  • Вопрос задан
  • 3152 просмотра
Решения вопроса 2
saboteur_kiev
@saboteur_kiev
software engineer
Множество if это нормально.

Для оптимизации, надо смотреть вашу задачу целиком. Возможно не хватает опыта или внимания, чтобы найти закономерности, которые можно сократить. Но возможно что их и нет.
Если условия такие разные, что их нельзя сократить, значит будет десять if и магия тут не поможет.

Можете кинуть все условия, вдруг кто-то что-то найдет.
Ответ написан
Комментировать
Если нужно избежать копирования кода с проверкой значений переменных, можно написать функцию с именем типа getCaseId, которая будет получать на вход ваши переменные и возвращать строковый идентификатор (или константу с идентификатором), по которому вам будет понятно, какой из случаев в данный момент имеет место. Потом составьте блок switch и в нём для каждого идентификатора пропишите нужные математические действия.

Это может быть полезно, если у вас в нескольких местах кода есть зависимость от значений этих переменных — можно повторно вызывать функцию getCaseId, если нужно, и использовать эти идентификаторы.
Ответ написан
Пригласить эксперта
Ответы на вопрос 4
uvelichitel
@uvelichitel
habrahabr.ru/users/uvelichitel
@asd111
Чтобы тебя больше не смущало большое количество if then else вот тебе пример кода из типичного лексера. Это не полный кусок и в нем больше 20 if then else и по другому писать особо нет смысла.
void next() {
        ...
        else if (token == '=') {
            // parse '==' and '='
            if (*src == '=') {
                src ++;
                token = Eq;
            } else {
                token = Assign;
            }
            return;
        }
        else if (token == '+') {
            // parse '+' and '++'
            if (*src == '+') {
                src ++;
                token = Inc;
            } else {
                token = Add;
            }
            return;
        }
        else if (token == '-') {
            // parse '-' and '--'
            if (*src == '-') {
                src ++;
                token = Dec;
            } else {
                token = Sub;
            }
            return;
        }
        else if (token == '!') {
            // parse '!='
            if (*src == '=') {
                src++;
                token = Ne;
            }
            return;
        }
        else if (token == '<') {
            // parse '<=', '<<' or '<'
            if (*src == '=') {
                src ++;
                token = Le;
            } else if (*src == '<') {
                src ++;
                token = Shl;
            } else {
                token = Lt;
            }
            return;
        }
        else if (token == '>') {
            // parse '>=', '>>' or '>'
            if (*src == '=') {
                src ++;
                token = Ge;
            } else if (*src == '>') {
                src ++;
                token = Shr;
            } else {
                token = Gt;
            }
            return;
        }
        else if (token == '|') {
            // parse '|' or '||'
            if (*src == '|') {
                src ++;
                token = Lor;
            } else {
                token = Or;
            }
            return;
        }
        else if (token == '&') {
            // parse '&' and '&&'
            if (*src == '&') {
                src ++;
                token = Lan;
            } else {
                token = And;
            }
            return;
        }
        else if (token == '^') {
            token = Xor;
            return;
        }
        else if (token == '%') {
            token = Mod;
            return;
        }
        else if (token == '*') {
            token = Mul;
            return;
        }
        else if (token == '[') {
            token = Brak;
            return;
        }
        else if (token == '?') {
            token = Cond;
            return;
        }
        else if (token == '~' || token == ';' || token == '{' || token == '}' || token == '(' || token == ')' || token == ']' || token == ',' || token == ':') {
            // directly return the character as token;
            return;
        }

        ...
}
Ответ написан
@Valera221
Делаю сайты
Можно сократить с помощью циклов for, while и массивов. Но желательно видеть как выглядит твой код.
Ответ написан
Комментировать
@zkrvndm
Софт для автоматизации
Вы можете загнать ваши условия в массив, используя Boolean, а затем красиво обработать все if внутри одного цикла for просто перебрав результирующий массив.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы