Заменить Temp запросом

Метод рефакторинга Replace Temp with Query сейчас рекомендуется довольно широко, но кажется очень неэффективным с очень небольшой прибылью.

Метод с сайта Мартина Фаулера дает следующий пример:

Извлеките выражение в метод. Замените все ссылки на temp выражением. Затем новый метод можно использовать в других методах.

    double basePrice = _quantity * _itemPrice;
    if (basePrice > 1000)
        return basePrice * 0.95;
    else
        return basePrice * 0.98;

становится

    if (basePrice() > 1000)
        return basePrice() * 0.95;
    else
        return basePrice() * 0.98;


double basePrice() {
    return _quantity * _itemPrice;
} 

Почему это хорошая идея? конечно, это означает, что вычисление без необходимости повторяется, и у вас есть накладные расходы на вызов функции. Я знаю циклы процессора дешевы, но выбрасывать их так небрежно?

Я что-то упускаю?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
13
0
3 005
8

Ответы 8

Он призван более полно раскрыть цель кода. В некоторых случаях им можно злоупотреблять, но маловероятно. например, вы можете обновить запросы о скидках 5% и 2% запросами, но в названии методов вы можете описать в названии причину скидки. помните, сегодня это может быть очевидным, но через 6 месяцев это может быть не так - как я уже сказал - дело не в том, что я забуду, а в том, когда я забуду.

  if (basePrice() > 1000)
     return bigTicketDiscount()
  else
     return regularDiscount()

double bigTicketDiscount(){
  return basePrice() * 0.95;
}

double regularDiscount(){
  return basePrice() * 0.98
}

Проблема в том, что если вы прочитаете страницу Фаулера по этому вопросу (ссылка в моем ответе), вы увидите, что код, указанный в вопросе (который, как вы подразумеваете, злоупотребляет этой концепцией), исходит непосредственно от Фаулера. Ваше предложение, похоже, меняет фокус того, что, похоже, говорит Фаулер.

James Curran 26.11.2008 18:05

Моя точка зрения на злоупотребления заключалась в том, что это возможно, если вы начнете делать это в крайнем случае, это нехорошо, и я мог видеть злоупотребления. Я думаю, что его намерение состоит в том, чтобы упростить код, который является сложным и непонятным - в конце концов, это метод, и если он не работает для вас, не делайте этого.

MikeJ 26.11.2008 18:26

Мне действительно кажется, что, делая это, вы помогаете достичь единой цели вашего исходного метода; Он больше не отвечает за расчет basePrice и скидки (или того, что он рассчитывает). Это пример того, как жертвовать некоторыми циклами ЦП, чтобы сделать код более удобным для сопровождения. «Потраченные впустую» циклы процессора, вероятно, не то, что вы заметите для одного, а также возможно, что компилятор может оптимизировать его (возможно, заметив, что метод относительно прост, и вместо вызова метода он вставляет фактический код (больше похоже на В любом случае, эти типы оптимизаций лучше оставить машинам, оставив людям работать над более чистым кодом.

Пример Джеймса Каррана достаточно ясен для большинства, не так ли? Я думаю, что это даст наибольшее «значение для циклов ЦП»: для ЦП это всего на 1 скачок стека дороже, но вы по-прежнему получаете удобочитаемость.

bungrudi 13.01.2011 05:16

Прочитав веб-страница на нем Фаулера, я не вижу преимуществ в том, чтобы делать это таким образом. Единственный возможный выигрыш - это изолировать выражение, которое может часто использоваться, в одном месте, но с этим лучше всего справиться:

    double basePrice = basePrice();
    if (basePrice > 1000)
            return basePrice * 0.95;
    else
            return basePrice * 0.98;

Фаулер не предлагает никаких объяснений, почему его исправленный код лучше оригинала, кроме как читать его книгу.

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

CodyBugstein 02.05.2013 18:50

Спасибо за размышления и за то, что пролили свет, но если вы хотите дать на это авторитетный ответ, то, по крайней мере, вы должны ИМЕТЬ (прочитать) книгу Фаулера, поскольку ваша ссылка на его веб-версию просто предоставляет ту же информацию, что и ОП. вопрос уже предусмотрен. Я считаю, что @Kenno и другие ответы превосходят этот.

Bart 11.02.2020 02:30

Я думаю, что большая часть полезности этого рефакторинга заключается не в его применении как таковом, а в качестве шага к методу извлечения, который является чрезвычайно распространенным и полезным. В тех случаях, когда локальная переменная мешает извлечению метода или усложняет его дополнительными параметрами, «замените временную переменную на подсказку», чтобы упростить извлечение метода. Также в этих случаях созданный метод запроса повторно используется двумя разными методами, которые являются результатом метода извлечения.

Есть еще кое-что о замене Temp запросом в книге рефакторинга, и это:

You may be concerned about performance in this case. As with other performance issues, let it slide for the moment. Nine times out of ten, it won't matter. When it does matter, you will fix the problem during optimization. With your code better factored, you will often find more powerful optimizations, which you would have missed without refactoring. If worse comes to worse, it's very easy to put the temp back.

Это рефакторинг, который важен, поскольку это рефакторинг в сторону единственной ответственности, это решение DRY fail!

Основная проблема с темпами (особенно в наивном коде, использующем длинные методы, длиной в сотни строк!) Заключается в том, что они являются изменяемыми, локальными состояниями. Очевидный риск (как обсуждал Фаулер?) Состоит в том, что кто-то может внести изменения в середине длинного метода и что-то сломать в конце. (Видели понесенные затраты)

Нет никаких тестов, у этого метода множество зависимостей - какой бардак! :)

Remove temp - это рефакторинг в сторону единоличной ответственности.

Пример - сегодня я обнаружил ошибку, связанную с передачей неправильная временная переменная в службу. Если я удалю temps (их несколько, все строки), эта ошибка (недосмотр) просто не может произойти.

Причина, по которой мой метод содержит временную переменную, заключается в том, что он выполняет работу, которой не должен ... и эта логика повторяется в аналогичных классах ... все ли это согласовано? НЕТ!

Удалив temp, я также реорганизую код в класс с соответствующей ответственностью, который можно на 110% покрыть несколькими простыми тестами.

Нет огромного приспособления для проверки чего-то тривиального

Если я назову что-то дорогое, я верну результат как объект / агрегат значения. «Временный код», вероятно, должен быть усвоен агрегатом.

Так что удаление temp толкает вас на централизованную (единственную) ответственность -> SOLID!

Я сейчас перечитываю «Рефакторинг», и одной из причин является следующая цитата из конца Extract Method, стр.116.

Предыстория: он описывает, что Extract Method трудно, если код для извлечения использует локальные переменные.

Temporary variables often are so plentiful that they make extraction very awkward. In these cases I try to reduce the temps by using Replace Temp with Query (120). ...

Таким образом, один рефакторинг может зависеть от первого рефакторинга, который сам по себе неочевиден. Другой пример - Inline Method перед заменой Method with Method Object.

Вы (как первоначальный спрашивающий, так и Джеймс Карран) упускаете из виду, что в этом конкретном примере расчет не повторяется. Либо код идет вниз по одной ветви if и вызывает basePrice(), который выполняет расчет. Или код переходит в другую ветвь if, и там же выполняется расчет.

Умножение производится независимо, но все же только один раз. Как и во временной версии.

Да, хорошо знать, что запросы по умолчанию не кэшируются и что временные файлы по своей сути являются формой кеширования. В этом конкретном примере это различие не имеет значения. Преимущество кеширования (например, temps) состоит в том, что оно может обеспечить экономию цикла ЦП (не совсем в этом случае, если говорить о самом умножении, я имею в виду - с точки зрения вызовов, скачков стека и т. компилятор). Недостатком кеширования является то, что оно может дать вам устаревшие или неверные данные, если вы небрежны. Это в дополнение к определенным недостаткам темпов, которые упоминает Фаулер (что они локальны, как во времени, так и в лексике).

Обычно я кодирую в запросах большую часть времени, и когда я вижу, что делать вызывает конкретный запрос несколько раз (в отличие от этого примера, где он находится в отдельных условных ветвях), я могу использовать временную, если она локальная или вводить мемоизация или другой тип системы кеширования (например, простая глобальная переменная или член класса), если мне нужно получить к ней доступ в более широкой, менее локальной области.

Вот тогда и пригодится обратный рефакторингу - «Заменить запрос на временный».

Оцените идею temps как формы кеширования. Но у вас все еще есть одно дополнительное вычисление для температуры в условии if.

ThomasH 13.05.2019 17:59

Что ж, это специфично для этого конкретного случая, в котором я бы использовал запрос. Я использую темп, когда он типа frotz = SuperExpensive(); if frotz = baz then frotz+bar, else frotz-bar или ж / д

Sandra 15.05.2019 08:13

Другие вопросы по теме