Согласно принятому ответу « Обоснование предпочтения локальных переменных переменным экземпляра? », Переменные должны жить в наименьшей возможной области видимости.
Упростите проблему в моей интерпретации, это означает, что мы должны реорганизовать такой код:
public class Main {
private A a;
private B b;
public ABResult getResult() {
getA();
getB();
return ABFactory.mix(a, b);
}
private getA() {
a = SomeFactory.getA();
}
private getB() {
b = SomeFactory.getB();
}
}
во что-то вроде этого:
public class Main {
public ABResult getResult() {
A a = getA();
B b = getB();
return ABFactory.mix(a, b);
}
private getA() {
return SomeFactory.getA();
}
private getB() {
return SomeFactory.getB();
}
}
но согласно «духу» «переменные должны жить в наименьшей возможной области видимости», разве «никогда не иметь переменные» имеют меньшую область действия, чем «иметь переменные»? Поэтому я думаю, что приведенная выше версия должна быть реорганизована:
public class Main {
public ABResult getResult() {
return ABFactory.mix(getA(), getB());
}
private getA() {
return SomeFactory.getA();
}
private getB() {
return SomeFactory.getB();
}
}
так что getResult()
вообще не имеет локальных переменных. Это правда?
refactoring
scope
local-variable
ocomfd
источник
источник
final
ключевое слово или нет.Ответы:
Нет. Есть несколько причин, почему:
И так далее.
источник
var taxIndex = getTaxIndex();
).now()
,) удаление переменной и вызов метода более одного раза может привести к ошибкам. Это может создать ситуацию, которая действительно тонкая и сложная для отладки. Это может показаться очевидным, но если вы выполняете слепую миссию по рефакторингу, чтобы удалить переменные, легко в конечном итоге ввести недостатки.Согласитесь, следует избегать переменных, которые не являются необходимыми и не улучшают читабельность кода. Чем больше переменных находится в области видимости в данном месте кода, тем сложнее понять этот код.
Я на самом деле не вижу преимущества переменных
a
иb
в вашем примере, поэтому я бы написал версию без переменных. С другой стороны, функция настолько проста, во-первых, я не думаю, что она имеет большое значение.Это становится больше проблемой, чем дольше функция становится и чем больше переменных находится в области видимости.
Например, если у вас есть
На вершине более крупной функции вы увеличиваете умственную нагрузку понимания остальной части кода, вводя три переменные, а не одну. Вы должны прочитать остальную часть кода, чтобы увидеть, если
a
илиb
используются снова. Локальные данные, которые находятся в области действия дольше, чем нужно, плохо влияют на общую читабельность.Конечно, в случае, когда переменная необходима (например, для хранения временного результата) или когда переменная действительно улучшает читабельность кода, ее следует сохранить.
источник
var result = getResult(...); return result;
то, что вы можете установить точку остановаreturn
и узнать, что именноresult
.В дополнение к другим ответам я хотел бы указать еще кое-что. Преимущество сохранения небольшой области действия переменной состоит не только в том, что синтаксически код имеет доступ к переменной, но и в уменьшении количества возможных путей потока управления, которые могут потенциально изменить переменную (либо путем присвоения ей нового значения, либо путем вызова метод мутирования существующего объекта в переменной).
Переменные в классе (экземпляр или статические) имеют значительно больше возможных путей потока управления, чем переменные в локальной области, потому что они могут быть изменены методами, которые могут вызываться в любом порядке, любое количество раз и часто кодом вне класса. ,
Давайте посмотрим на ваш начальный
getResult
метод:Теперь имена
getA
иgetB
могут предложить , что они будут назначатьthis.a
иthis.b
мы не можем знать наверняка , от просто глядяgetResult
. Таким образом, возможно , чтоthis.a
иthis.b
значение , передаваемое вmix
метод , а не исходить от состоянияthis
объекта, чем преждеgetResult
было вызвано, что невозможно предсказать , так как клиенты контролировать , как и когда методы называются.В пересмотренном коде с локальными
a
иb
переменными ясно, что существует ровно один (без исключений) поток управления от присваивания каждой переменной ее использованию, потому что переменные объявляются непосредственно перед их использованием.Таким образом, существует существенное преимущество перемещения (изменяемых) переменных из области классов в локальную область (а также перемещения (изменяемых) переменных из внешней части цикла во внутреннюю) в том, что это упрощает рассуждение потока управления.
С другой стороны, исключение переменных, как в вашем последнем примере, дает меньшую выгоду, поскольку на самом деле это не влияет на рассуждения потока управления. Вы также теряете имена, присвоенные значениям, чего не происходит при простом перемещении переменной во внутреннюю область. Это компромисс, который вы должны учитывать, поэтому устранение переменных может быть лучше в одних случаях и хуже в других.
Если вы не хотите терять имена переменных, но по-прежнему хотите уменьшить область видимости переменных (в случае их использования внутри большой функции), вы можете рассмотреть оборачивание переменных и их использование в операторе блока ( или перемещая их к их собственной функции ).
источник
Это в некоторой степени зависит от языка, но я бы сказал, что одно из менее очевидных преимуществ функционального программирования заключается в том, что оно поощряет программиста и читателя кода к тому, что они не нужны. Рассмотреть возможность:
Или какой-нибудь LINQ:
Или Node.js:
Последний представляет собой цепочку вызова функции по результату предыдущей функции без каких-либо промежуточных переменных. Введение их сделало бы это намного менее ясным.
Однако различие между первым примером и двумя другими заключается в предполагаемом порядке работы . Это может не совпадать с порядком, который он фактически вычислен, но это порядок, в котором читатель должен думать об этом. Для вторых двух это слева направо. Для примера Lisp / Clojure это больше похоже на справа налево. Вы должны быть немного осторожны при написании кода, который не является «направлением по умолчанию» для вашего языка, и определенно следует избегать «промежуточных» выражений, которые смешивают эти два понятия.
Трубный оператор F #
|>
полезен отчасти потому, что он позволяет писать вещи слева направо, которые в противном случае должны были бы быть справа налево.источник
myCollection.Select(_ => _.SomeProp).Where(_ => _.Size > 4);
Я бы сказал нет, потому что вы должны читать «наименьшую возможную область» как «среди существующих областей или областей, которые разумно добавить». В противном случае это будет означать, что вы должны создавать искусственные области видимости (например, безвозмездные
{}
блоки в C-подобных языках) только для того, чтобы гарантировать, что область действия переменной не выходит за пределы последнего предполагаемого использования, и это, как правило, будет восприниматься как запутывание / беспорядок, если уже нет хорошая причина для того, чтобы сфера существовала независимо.источник
Рассмотрим функции ( методы ). Там нет ни разбиения кода на наименьшую возможную подзадачу, ни самого большого одиночного фрагмента кода.
Это смещающий предел с разделением логических задач на расходные части.
То же самое верно для переменных . Выделение логических структур данных на понятные части. Или также просто назвав (заявив) параметры:
Но, конечно, с объявлением вверху и двумя сотнями строк, первое использование в настоящее время считается плохим стилем. Это ясно, что «переменные должны жить в наименьшей возможной области» намеревается сказать. Как очень близко "не используйте переменные повторно".
источник
Чего не хватает в качестве причины для НЕТ, так это отладки / читабельности. Код должен быть оптимизирован для этого, и четкие и краткие имена очень помогают, например, представьте 3 способа, если
эта строка короткая, но уже трудно читать. Добавьте еще несколько параметров, и это, если охватывает несколько строк.
Я считаю, что этот способ легче читать и передавать смысл, поэтому у меня нет проблем с промежуточными переменными.
Другим примером могут быть такие языки, как R, где последняя строка автоматически возвращает значение:
это опасно, возврат ожидается или нужен? это понятнее
Как всегда, это суждение - исключить промежуточные переменные, если они не улучшают чтение, в противном случае сохраните или введите их.
Другим моментом может быть возможность отладки: если промежуточные результаты представляют интерес, лучше всего просто ввести посредника, как в приведенном выше примере R. Как часто это требуется, трудно себе представить, и будьте осторожны с тем, что вы регистрируете - слишком много отладочных переменных сбивают с толку - опять же, вызов суждения.
источник
Обращаясь только к вашему названию: абсолютно, если переменная не нужна, ее следует удалить.
Но «ненужное» не означает, что эквивалентная программа может быть написана без использования переменной, в противном случае нам сказали бы, что мы должны писать все в двоичном виде.
Самым распространенным видом ненужных переменных является неиспользуемая переменная: чем меньше область действия переменной, тем легче определить, что она не нужна. Трудно определить, нужна ли промежуточная переменная, потому что это не бинарная ситуация, а контекстная. Фактически идентичный исходный код в двух разных методах может давать разные ответы одного и того же пользователя в зависимости от прошлого опыта исправления проблем в окружающем коде.
Если ваш пример кода был в точности таким, как он представлен, я бы предложил избавиться от двух приватных методов, но не стал бы беспокоиться о том, сохранили ли вы результат фабричных вызовов в локальной переменной или просто использовали их в качестве аргументов в миксе. метод.
Читаемость кода превосходит все, кроме правильной работы (правильно включает приемлемые критерии производительности, которые редко бывают «максимально быстрыми»).
источник