Рефакторинг: выделение временной переменной в метод
Продолжаем тему рефакторинга, и сегодня рассмотрим такой прием, как замена временной переменной методом (функцией).
Показания к применению
Если Вы используете временную переменную для хранения результата какого-то выражения, Вам необходимо поместить это выражение в отдельную функцию (метод) таким образом, что эта функция может быть в дальнейшем использована в других функциях. Дело в том, что такие временные переменные усложняют код метода, в котором они используются. Путем замены временной переменной методом любой метод затем сможет использовать результат, возвращенный новым созданным методом. Это очень помогает в процессе очистки кода в классе.
Данный прием является крайне необходимым, если Вы собираетесь применить такую технику рефакторинга, как «Группировка кода в отдельную функцию». Локальные переменные усложняют применение данного приема. Об этом приеме мы поговорим в одной из следующих статей.
Прием выделения временной переменной в отдельный метод применяется только если у нас есть временная переменная, которой значение присваивается единожды, а также если в выражении, которое присваивается переменной, нет чего-то такого, что мы бы назвали побочными явлениями. В этих случаях перед применением этой техники можно применить такие методы рефакторинга, как избавление от временных переменных и разделение функции. Если наша переменная подсуммирует (для примера) какое-то значение в цикле, то придется в новую выделяемую функцию добавить какие-то условия.
Применение
- Найдите временную переменную, которой значение присваивается только один раз. Если значение ей присваивается больше одного раза, то примените прием избавления от временных переменных.
- Выделите правую часть присваивания в отдельную функцию.
- Отметьте новый метод как private. Если в дальнейшем обнаружится, что его можно использовать не только внутри класса, то в будущем не будет ничего сложного объявить его public.
- Убедитесь, что новый метод не имеет побочных эффектов, т.е. не модифицирует какой-то объект. Если побочные эффекты имеются, примените технику разделения функции.
- Замените все использования этой переменной использованием новой функции.
- Протестируйте работу скрипта (программы).
Например, продемонстрирую следующий кусок кода (взятый из какого-то метода какого-то класса):
$basePrice = $_qty * $_itemPrice; if ($basePrice > 500) { return $basePrice * 0.95; } else { return $basePrice * 0.98; }
Следуя нашему приему, мы должны превратить наш код в такой:
if (basePrice() > 500) { return basePrice() * 0.95; } else { return basePrice() * 0.98; } function basePrice() { return $_qty * $_itemPrice; }
Зачастую, временные переменные используются для подсуммирования результата в циклах. В этом случае мы можем весь цикл выделить в отдельную функцию.
Вам может показаться, что этот прием сильно сказывается на производительности. Может это и действительно так, но в дальнейшем никто Вам не помешает оптимизировать отрефакторенный код. Причем, мы уже говорили статьями ранее, что оптимизация после проведения рефакторинга дает лучшие результаты, чем если бы мы его не проводили.
Приведу тот же самый пример, но немного усложню его. Пусть у нас есть метод:
function getPrice() { $basePrice = $_qty * $_itemPrice; if ($basePrice > 500) { $discountFactor = 0.95; } else { $discountFactor = 0.98; } return $basePrice * $discountFactor; }
Здесь у нас есть две временные переменные: $basePrice и $discountFactor. Сначала выделим выражение переменной $basePrice в отдельный метод basePrice():
function getPrice() { $basePrice = basePrice(); if ($basePrice > 500) { $discountFactor = 0.95; } else { $discountFactor = 0.98; } return $basePrice * $discountFactor; } function basePrice() { return $_qty * $_itemPrice; }
Проверяем работу скрипта. Работает. Далее заменяем $basePrice вызовом basePrice():
function getPrice() { if (basePrice() > 500) { $discountFactor = 0.95; } else { $discountFactor = 0.98; } return basePrice() * $discountFactor; }
Теперь выделим вторую временную переменную - $discountFactor - в отдельный метод discountFactor():
function getPrice() { $discountFactor = discountFactor(); return basePrice() * $discountFactor; } function discountFactor() { if (basePrice() > 500) { return 0.95; } return 0.98; }
Заметьте, что нам тяжелее было бы выделять discountFactor(), если бы мы предварительно не выделили basePrice().
В итоге, метод getPrice() у нас выглядит следующим образом:
function getPrice() { return basePrice() * discountFactor(); }
На сегодня все. В следующий раз мы рассмотрим такой прием рефакторинга, как «Группировка кода в отдельную функцию».
Удачи!
Путевая статья.