Selon la réponse acceptée sur " Justification de préférer les variables locales aux variables d'instance? ", Les variables devraient vivre dans la plus petite portée possible.
Simplifier le problème dans mon interprétation, cela signifie que nous devrions reformer ce type de code:
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();
}
}
dans quelque chose comme ça:
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();
}
}
mais selon "l'esprit" de "les variables doivent vivre dans la plus petite portée possible", "les variables n'ayant jamais" n'ont-elles pas une portée plus petite que "les variables"? Je pense donc que la version ci-dessus devrait être refactorisée:
public class Main {
public ABResult getResult() {
return ABFactory.mix(getA(), getB());
}
private getA() {
return SomeFactory.getA();
}
private getB() {
return SomeFactory.getB();
}
}
donc cela getResult()
n'a pas de variables locales du tout. Est-ce vrai?
refactoring
scope
local-variable
ocomfd
la source
la source
final
mot-clé ou non.Réponses:
Non, il y a plusieurs raisons pour lesquelles:
Etc.
la source
var taxIndex = getTaxIndex();
).now()
,), supprimer la variable et appeler la méthode plusieurs fois peut entraîner des bogues. Cela peut créer une situation très subtile et difficile à déboguer. Cela peut sembler évident, mais si vous êtes dans une mission de refactoring à l'aveugle pour supprimer des variables, il est facile d'introduire des failles.D'accord, les variables qui ne sont pas nécessaires et n'améliorent pas la lisibilité du code devraient être évitées. Plus il y a de variables qui entrent dans la portée à un moment donné du code, plus ce code est complexe à comprendre.
Je ne vois pas vraiment l'avantage des variables
a
etb
dans votre exemple, j'écrirais donc la version sans variables. D'un autre côté, la fonction est si simple au départ que je ne pense pas que cela compte beaucoup.Plus la fonction est longue et plus la portée des variables est longue, plus le problème est complexe.
Par exemple si vous avez
Au sommet d'une fonction plus importante, vous augmentez la charge mentale de comprendre le reste du code en introduisant trois variables plutôt qu'une. Vous devez lire le reste du code pour voir si
a
oub
sont utilisés à nouveau. Les sections locales dont la portée est plus longue que nécessaire ne nuisent pas à la lisibilité générale.Bien sûr , dans le cas où une variable est nécessaire (par exemple pour stocker un résultat temporaire) ou si une variable n'améliorer la lisibilité du code, il doit être conservé.
la source
var result = getResult(...); return result;
celle-ci, est que vous pouvez placer un point d'arrêtreturn
et apprendre ce queresult
c'est exactement .En plus des autres réponses, je voudrais signaler autre chose. L’avantage de limiter la portée d’une variable n’est pas simplement de réduire le nombre de codes ayant accès à la variable dans la syntaxe, mais également de réduire le nombre de chemins de contrôle pouvant éventuellement modifier une variable (en lui affectant une nouvelle valeur ou en appelant une nouvelle méthode). une méthode de mutation sur l'objet existant contenu dans la variable).
Les variables à portée de classe (instance ou statique) ont beaucoup plus de chemins de flux de contrôle possibles que les variables à portée locale, car elles peuvent être mutées par des méthodes pouvant être appelées dans n'importe quel ordre, nombre de fois, et souvent par code en dehors de la classe. .
Jetons un coup d'oeil à votre
getResult
méthode initiale :Maintenant, les noms
getA
etgetB
peuvent suggérer qu’ils assigneront àthis.a
etthis.b
, nous ne pouvons pas savoir avec certitude en regardant simplementgetResult
. Ainsi, il est possible que les valeursthis.a
etthis.b
passées dans lamix
méthode proviennent plutôt de l'état de l'this
objet avant qu'il aitgetResult
été appelé, ce qui est impossible à prédire puisque les clients contrôlent comment et quand les méthodes sont appelées.Dans le code révisé avec les variables locales
a
et localesb
, il est clair qu'il existe exactement un flux de contrôle (sans exception) de l'affectation de chaque variable à son utilisation, car les variables sont déclarées juste avant leur utilisation.Ainsi, le fait de déplacer des variables (modifiables) d'une classe à une autre (ainsi que de déplacer des variables (modifiables) de l'extérieur d'une boucle à l'intérieur) présente un avantage important, en ce sens qu'il simplifie le raisonnement du contrôle-flux.
En revanche, éliminer les variables comme dans votre dernier exemple présente moins d'avantages, car cela n'affecte pas vraiment le raisonnement du contrôle-flux. Vous perdez également les noms attribués aux valeurs, ce qui ne se produit pas lorsque vous déplacez simplement une variable dans une portée interne. C’est un compromis que vous devez prendre en compte. Par conséquent, l’élimination des variables peut être meilleure dans certains cas et pire dans d’autres.
Si vous ne voulez pas perdre les noms de variables, mais que vous voulez tout de même réduire la portée des variables (si elles sont utilisées dans une fonction plus grande), vous pouvez envisager de regrouper les variables et leurs utilisations dans une instruction block ( ou les déplacer à leur propre fonction ).
la source
Cela dépend un peu de la langue, mais je dirais que l’un des avantages moins évidents de la programmation fonctionnelle est qu’elle encourage le programmeur et le lecteur de code à ne pas en avoir besoin. Considérer:
Ou un peu de LINQ:
Ou Node.js:
La dernière est une chaîne d'appels d'une fonction sur le résultat d'une fonction précédente, sans aucune variable intermédiaire. Leur présentation le rendrait beaucoup moins clair.
Cependant, la différence entre le premier exemple et les deux autres correspond à l' ordre implicite de fonctionnement . Ce n'est peut-être pas le même ordre que l'ordre dans lequel il a été calculé, mais c'est l'ordre dans lequel le lecteur devrait y réfléchir. Pour les deux autres, cela va de gauche à droite. Pour l'exemple Lisp / Clojure, c'est plus comme de droite à gauche. Vous devriez vous méfier de l'écriture de code qui n'est pas dans la "direction par défaut" de votre langue, et les expressions de "moyen terme" qui mélangent les deux doivent absolument être évitées.
L’opérateur de pipe de F #
|>
est utile en partie parce qu’il vous permet d’écrire des choses de gauche à droite qui devraient sinon être de droite à gauche.la source
myCollection.Select(_ => _.SomeProp).Where(_ => _.Size > 4);
Je dirais non, car vous devriez lire "la plus petite portée possible" comme "parmi les portées existantes ou celles qu'il est raisonnable d'ajouter". Sinon, cela impliquerait que vous créiez des portées artificielles (par exemple, des
{}
blocs gratuits dans des langages de type C) juste pour vous assurer que la portée d'une variable ne dépasse pas la dernière utilisation prévue, et que cela serait généralement mal vu, à moins qu'il n'y ait déjà une bonne raison pour que le champ existe indépendamment.la source
Considérons les fonctions ( méthodes ). Il ne divise pas le code dans la plus petite sous-tâche possible, ni le plus gros morceau de code singleton.
Il s'agit d'une limite de déplacement, avec délimitation de tâches logiques, en éléments consommables.
La même chose vaut pour les variables . Mise en évidence des structures de données logiques, dans des parties compréhensibles. Ou aussi simplement nommer (énoncer) les paramètres:
Mais bien sûr, avec une déclaration en haut et deux cents lignes plus loin, le premier usage est de nos jours considéré comme un mauvais style. C’est clairement ce que «les variables doivent vivre dans le plus petit champ possible», entend-on dire. Comme un très proche "ne pas réutiliser les variables."
la source
Ce qui manque quelque peu en tant que raison pour NO est le débogage / la capacité de lecture. Le code doit être optimisé pour cela, et des noms clairs et concis aident beaucoup, par exemple, imaginez trois façons si
cette ligne est courte, mais déjà difficile à lire. Ajoutez quelques paramètres supplémentaires, et cela si s'étend sur plusieurs lignes.
Je trouve cette manière plus facile de lire et de communiquer le sens - je n’ai donc aucun problème avec les variables intermédiaires.
Un autre exemple serait celui de langues telles que R, où la dernière ligne est automatiquement la valeur de retour:
c'est dangereux, le retour est-il prolongé ou nécessaire? c'est plus clair:
Comme toujours, il s’agit d’un jugement: éliminez les variables intermédiaires si elles n’améliorent pas la lecture, sinon conservez-les ou introduisez-les.
La débogage est un autre point: si les résultats intermédiaires sont intéressants, il peut être préférable d’introduire simplement un intermédiaire, comme dans l’exemple R ci-dessus. Il est difficile d'imaginer combien de fois cela est nécessaire et faites attention à ce que vous archivez - trop de variables de débogage prêtent à confusion - encore une fois, un jugement.
la source
En se référant uniquement à votre titre: absolument, si une variable est inutile, elle doit être supprimée.
Mais «inutile» ne signifie pas qu'un programme équivalent peut être écrit sans utiliser la variable, sinon on nous dirait qu'il faut tout écrire en binaire.
Le type le plus courant de variable non nécessaire est une variable non utilisée. Plus la portée de la variable est petite, plus il est facile de déterminer qu’elle est inutile. Il est plus difficile de déterminer si une variable intermédiaire est inutile, car il ne s'agit pas d'une situation binaire, mais contextuelle. En fait, un code source identique dans deux méthodes différentes pourrait produire une réponse différente par le même utilisateur, en fonction de l'expérience acquise en matière de résolution de problèmes dans le code environnant.
Si votre code d'exemple était exactement tel qu'il était représenté, je vous suggérerais de vous débarrasser des deux méthodes privées, sans vous soucier de savoir si vous avez enregistré le résultat des appels d'usine à une variable locale ou si vous les avez simplement utilisés comme arguments du mélange. méthode.
La lisibilité du code prime sur tout sauf sur le fait de fonctionner correctement (inclut correctement les critères de performance acceptables, qui sont rarement «aussi rapides que possible»).
la source