В прошлом выпуске мы поделились своим пониманием equals и hashCode в Java.
В этом выпуске мы поделимся обработкой сложной логики if/else в Java.
Я видел некоторые вопросы на github.Иностранные программисты больше не пишут что-то еще, и я видел много таких комментариев.
else is horrible
, то для сегмента кода с очень сложной логикой, если используется слишком много операторов if/else, это затруднит чтение кода и в то же время увеличит размер кода.圈复杂度
, По идее, если цикломатическая сложность функции превышает 8, то эта функция еще имеет место для оптимизации, так как же оптимизировать эту многоветвевую сложную логическую функцию? В инструкции приведены три метода:卫语句
,策略模式
,状态模式
, чтением《重构:改善既有代码的设计》
Выяснено, что на самом деле существует много способов решения этой проблемы, и мы подойдем к ним один за другим ниже.
Категория 1: реорганизация функций
1. Метод извлечения
Этот метод должен быть одним из наиболее часто используемых.Когда функция слишком длинная или имеет слишком много ветвей, вы можете рассмотреть возможность выделения фрагмента кода в отдельную функцию.
- Оригинальный код:
public void today() {
if (isBusy()) {
System.out.println("change time.");
} else if (isFree()) {
System.out.println("go to travel.");
} else {
System.out.println("stay at home to learn Alibaba Java Coding Guidelines.");
}
}
- Модифицированный код:
public void today() {
if (isBusy()) {
changeTime();
} else if (isFree()) {
goToTravel();
} else {
stayAtHomeToLearn();
}
}
private void changeTime() {
System.out.println("change time.");
}
private void goToTravel() {
System.out.println("go to travel.");
}
private void stayAtHomeToLearn() {
System.out.println("stay at home to learn Alibaba Java Coding Guidelines.");
}
Применение:
- Выделите новые функции, назовите их в соответствии с тем, для чего функция предназначена, и назовите их в честь того, что они делают, а не как они это делают.
- Дважды проверьте, что извлеченный код ссылается на переменные, относящиеся к исходной функции, включая локальные переменные и параметры исходной функции.
- Применимые сценарии: код слишком длинный для функций или требует комментариев, чтобы люди поняли цель
2. Substitute Algorithm (алгоритм замены)
Замените алгоритм другим, более чистым алгоритмом, или замените тело функции другим алгоритмом.
- Оригинальный код:
public String foundPerson(String[] people) {
for (int i = 0; i < people.length; i++) {
if (people[i].equals("Don")) {
return "Don";
}
if (people[i].equals("John")) {
return "John";
}
if (people[i].equals("Kent")) {
return "Kent";
}
}
return "";
}
- Модифицированный код:
public String foundPerson(String[] people) {
List<String> candidates = Arrays.asList(new String[] { "Don", "John", "Kent" });
for (int i = 0; i < people.length; i++) {
if (candidates.contains(people[i])) {
return people[i];
}
}
return "";
}
Применение:
- Подготовьте еще один альтернативный алгоритм
- Новый алгоритм должен иметь тот же результат, что и исходный алгоритм.
- Применимые сценарии: замените алгоритм более понятным алгоритмом или замените функцию алгоритмом.
Вторая категория: упрощение условных выражений
1. Eecompose Conditional (условное выражение декомпозиции)
Если есть сложные условные операторы (if-then-else), извлеките независимые функции из трех абзацев if, then и else.
- Оригинальный код:
public void today() {
if (isBusy() || isNotWeekend()) {
System.out.println("change time.");
return;
} else {
System.out.println("go to travel.");
}
}
- Модифицированный код:
public void today() {
if (notFree()) {
changeTime();
} else {
goToTravel();
}
}
private boolean notFree() {
return isBusy() || isNotWeekend();
}
private void changeTime() {
System.out.println("change time.");
}
private void goToTravel() {
System.out.println("go to travel.");
}
Применение:
- Извлеките абзац if, чтобы сформировать независимую функцию
- Извлеките абзац then и абзац else, каждый из которых образует независимую функцию.
- Применимые сценарии: сложные условные операторы. Если вы обнаружите вложенную условную логику, сначала посмотрите, можете ли вы использовать защитные операторы, а если нет, начните разбирать каждое условие в ней.
2. Консолидируйте условное выражение
Если у вас есть ряд условных тестов, которые все дают одинаковый результат, объедините тесты в условное выражение и преобразуйте это условное выражение в одну функцию.
- Оригинальный код:
public void today() {
if (isWeekend()) {
System.out.println("go to travel.");
}
if (isHoliday()) {
System.out.println("go to travel.");
}
if (noWork()) {
System.out.println("go to travel.");
}
}
- Модифицированный код:
public void today() {
if (isFree()) {
System.out.println("go to travel.");
}
}
private boolean isFree() {
return isWeekend() || isHoliday() || noWork();
}
Применение:
- Убедитесь, что ни один из этих условных операторов не имеет побочных эффектов.
- Объединяет ряд связанных условных выражений в одно, используя соответствующие логические операторы, и уточняет функцию объединенных выражений.
- Применимый сценарий: серия условных тестов, все они дают одинаковый результат.
3. Объедините повторяющиеся условные предложения
В каждой ветви условного выражения есть один и тот же фрагмент кода, переместите этот код за пределы условного выражения.
- Оригинальный код:
public void today() {
if (isBusy()) {
System.out.println("change time.");
sleep();
} else if (isFree()) {
System.out.println("go to travel.");
sleep();
} else {
System.out.println("stay at home to learn Alibaba Java Coding Guidelines.");
sleep();
}
}
- Модифицированный код:
public void today() {
if (isBusy()) {
System.out.println("change time.");
} else if (isFree()) {
System.out.println("go to travel.");
} else {
System.out.println("stay at home to learn Alibaba Java Coding Guidelines.");
}
sleep();
}
Применение:
- Определите код, выполнение которого не зависит от условий
- Если общий код находится в начале условного выражения, переместите его перед условным выражением, если в конце, переместите после условного выражения.
- Применимый сценарий: один и тот же фрагмент кода на каждой ветке условного выражения
4. Удалить контрольный флаг
В серии логических выражений переменная имеет функцию «управляющего флага (Flag)», а управляющий флаг заменяется оператором break или оператором return.
5. Замените Nested Confitional на Guard Clauses (замените вложенные условные выражения на Guard операторы)
Если несколько ветвей являются нормальным поведением, вы должны использовать условное выражение if...else... Если условие встречается очень редко, вы должны проверить условие отдельно и немедленно удалить функцию из функции, если условие истинно. Возвращаясь, такая отдельная проверка часто называется оператором защиты.
- Оригинальный код:
public void today() {
if (isBusy()) {
System.out.println("change time.");
} else if (isFree()) {
System.out.println("go to travel.");
} else {
System.out.println("stay at home to learn Alibaba Java Coding Guidelines.");
}
}
- Модифицированный код:
public void today() {
if (isBusy()) {
System.out.println("change time.");
return;
}
if (isFree()) {
System.out.println("go to travel.");
return;
}
System.out.println("stay at home to learn Alibaba Java Coding Guidelines.");
return;
}
Применение:
- Для каждой проверки поставьте охранный оператор, который либо возвращает функцию, либо выдает исключение.
- Компилируйте и тестируйте каждый раз после замены условных проверок охранниками: если все охранники приводят к одному и тому же результату, используйте
合并条件表达式
- Применимые сценарии: используйте операторы защиты для возврата всех особых случаев.
6. Замените условное выражение на полиморфизм
Условное выражение, выберите различные варианты поведения в соответствии с типом объекта, поместите каждую ветвь этого условного выражения в функцию переопределения в подпрограмме, а затем объявите исходную функцию как абстрактную функцию, это то, что говорится в руководстве Режим стратегии и режим состояния . Из-за полиморфизма в объектно-ориентированных программах редко появляются «операторы переключения с кодировкой типа» и «операторы if-then-else на основе имени типа».
Третья категория: упрощение вызовов функций
1. Отделить запрос от модификатора (отделить функцию запроса и функцию модификации)
Функция не только возвращает значение состояния объекта, но также изменяет состояние и устанавливает две разные функции, одна из которых отвечает за запрос, а другая — за модификацию.
- Параллельная ситуация: нужно сохранить третью функцию, чтобы делать обе вещи одновременно
2. Метод параметризации (пусть функция несет параметры)
Несколько функций выполняют аналогичную работу, но содержат разные значения в теле функции, создавая единую функцию, которая выражает эти разные значения в качестве параметров.
- Оригинальный код:
public void tenPercentRaise() {
salary *= 1.1;
}
public void fivePercentRaise() {
salary *= 1.05;
}
- Модифицированный код:
public void raise(double factor) {
salary *= (1 + factor);
}
- Суть в том, чтобы найти повторяющийся код, основываясь на том факте, что небольшое количество значений можно рассматривать как параметры.
3. Замените параметр явными методами (замените параметры явными функциями)
Чтобы иметь функцию, которая ведет себя по-разному в зависимости от значения параметра, создайте отдельную функцию для каждого возможного значения этого параметра.
- Оригинальный код:
public void setValue(String name, int value) {
if (name.equals("height")) {
height = value;
}
if (name.equals("width")) {
width = value;
}
}
- Модифицированный код:
public void setHeight(int arg) {
height = arg;
}
public void setWidth(int arg) {
width = arg;
}
Применение:
- Создайте явную функцию для каждого возможного значения параметра
- Измените каждую ветвь условного выражения, чтобы вызвать соответствующую новую функцию.
- Применимые сценарии: функции, которые ведут себя по-разному в зависимости от значений параметров