Rendre les méthodes qui ne dépendent pas des champs d'instance, statiques?

19

Récemment, j'ai commencé à programmer dans Groovy pour un framework de test d'intégration, pour un projet Java. J'utilise Intellij IDEA avec le plug-in Groovy et je suis surpris de voir comme un avertissement pour toutes les méthodes qui ne sont pas statiques et ne dépendent d'aucun champ d'instance. En Java, cependant, ce n'est pas un problème (du moins du point de vue de l'IDE).

Toutes les méthodes qui ne dépendent d'aucun champ d'instance doivent-elles être transformées en fonctions statiques? Si vrai, est-ce spécifique à Groovy ou est-il disponible pour la POO en général? Et pourquoi?

m3th0dman
la source
Ces méthodes appellent-elles d'autres méthodes d'instance? Ou n'ont-ils littéralement rien à voir avec un objet de cette classe? Pouvez-vous donner un exemple?
Ray Toal

Réponses:

26

Notez que IDEA a également cette inspection pour Java, elle est appelée Méthode peut être «statique» ,

Cette inspection rapporte toutes les méthodes qui peuvent être rendues statiques en toute sécurité. Une méthode peut être statique si elle ne fait référence à aucune des méthodes non statiques et des champs non statiques de sa classe et n'est pas remplacée dans une sous-classe ...

Le problème est que pour le code Java, cette inspection est désactivée par défaut (le programmeur peut l'activer à sa discrétion). La raison en est très probablement que la validité / l'utilité d'une telle inspection pourrait être contestée, sur la base de quelques sources très fiables.

Pour commencer, le tutoriel Java officiel est plutôt restrictif sur le moment où les méthodes doivent être statiques:

Une utilisation courante des méthodes statiques consiste à accéder aux champs statiques.

Étant donné ci-dessus, on pourrait faire valoir que l'activation de l'inspection mentionnée par défaut n'est pas conforme à l'utilisation recommandée du modificateur statique en Java.

En outre, il existe quelques autres sources qui vont jusqu'à suggérer une approche judicieuse pour utiliser les idées qui se cachent derrière cette inspection ou même la décourager.

Voir par exemple un article sur Java World - M. Happy Object enseigne les méthodes statiques :

Toute méthode indépendante de l'état d'instance est susceptible d'être déclarée comme statique.

Notez que je dis «candidat pour être déclaré statique». Même dans l'exemple précédent, rien ne vous oblige à déclarer instances()comme statique. Le déclarer comme statique le rend plus pratique à appeler car vous n'avez pas besoin d'une instance pour appeler la méthode. Parfois, vous aurez des méthodes qui ne semblent pas dépendre de l'état de l'instance. Vous ne voudrez peut-être pas rendre ces méthodes statiques. En fait, vous ne voudrez probablement les déclarer statiques que si vous devez y accéder sans instance.

De plus, même si vous pouvez déclarer une telle méthode comme statique, vous ne le voudrez peut-être pas en raison des problèmes d'héritage qu'elle interrompt dans votre conception. Jetez un œil à la "Conception efficace orientée objet" pour voir certains des problèmes auxquels vous serez confrontés ...

Un article sur le blog de test de Google va même jusqu'à affirmer que les méthodes statiques sont mortelles pour la testabilité :

Permet de faire un exercice mental. Supposons que votre application ne comporte que des méthodes statiques. (Oui, un code comme celui-là est possible d'écrire, c'est ce qu'on appelle la programmation procédurale.) Imaginez maintenant le graphe d'appel de cette application. Si vous essayez d'exécuter une méthode leaf, vous n'aurez aucun problème à configurer son état et à affirmer tous les cas d'angle. La raison en est qu'une méthode feuille ne fait plus d'appels. À mesure que vous vous éloignez des feuilles et que vous vous rapprochez de la main()méthode des racines , il sera de plus en plus difficile de configurer l'état dans votre test et de plus en plus d'affirmer les choses. Beaucoup de choses deviendront impossibles à affirmer. Vos tests deviendront progressivement plus grands. Une fois que vous atteignez lemain()méthode vous n'avez plus de test unitaire (car votre unité est l'application entière) vous avez maintenant un test de scénario. Imaginez que l'application que vous essayez de tester soit un traitement de texte. Il n'y a pas grand-chose que vous pouvez affirmer de la méthode principale ...

Parfois, une méthode statique est une fabrique pour d'autres objets. Cela exagère encore le problème des tests. Dans les tests, nous nous appuyons sur le fait que nous pouvons câbler les objets différemment en remplaçant les dépendances importantes par des simulations. Une fois qu'un newopérateur est appelé, nous ne pouvons pas remplacer la méthode par une sous-classe. Un appelant d'une telle usine statique est lié en permanence aux classes concrètes produites par la méthode de l'usine statique. En d'autres termes, les dommages de la méthode statique sont bien au-delà de la méthode statique elle-même. Butter le câblage et le code de construction d'un graphique d'objet dans une méthode statique est très mauvais, car le câblage d'un graphique d'objet est la façon dont nous isolons les choses pour les tests ...


Vous voyez, étant donné ci-dessus, il semble naturel que l'inspection mentionnée soit désactivée par défaut pour Java.

Les développeurs IDE auraient beaucoup de mal à expliquer pourquoi ils pensent qu'il est si important de l'activer par défaut, contre des recommandations et des meilleures pratiques largement reconnues.

Pour Groovy, les choses sont assez différentes. Aucun des arguments énumérés ci-dessus ne s'applique, en particulier celui sur la testabilité, comme expliqué par exemple dans Mocking Static Methods dans l' article Groovy de Javalobby:

Si la classe Groovy que vous testez appelle une méthode statique sur une autre classe Groovy, vous pouvez utiliser la ExpandoMetaClass qui vous permet d'ajouter dynamiquement des méthodes, des constructeurs, des propriétés et des méthodes statiques ...

Cette différence est probablement la raison pour laquelle le paramètre par défaut pour l'inspection mentionnée est opposé dans Groovy. Alors qu'en Java par défaut "on" serait source de confusion pour les utilisateurs, dans Groovy, un paramètre opposé pourrait confondre les utilisateurs IDE.

"Hé, la méthode n'utilise pas de champs d'instance, pourquoi ne m'as-tu pas prévenu?" Il serait facile de répondre à cette question pour Java (comme expliqué ci-dessus), mais pour Groovy, il n'y a tout simplement pas d'explication convaincante.

moucheron
la source
Soit dit en passant, ReSharper (réalisé par JetBrains pour C # / Visual Studio) suggère la même chose
Konrad Morawski
6
Il existe une distinction importante entre les méthodes statiques avec et sans effets secondaires. L'extrait de Google s'adresse vraiment au premier.
assylias
@assylias C'est le cas, mais il explique également comment les méthodes d'usine peuvent rendre les tests plus difficiles (car elles couplent étroitement les dépendances dans l'application). L'utilisation d'une infrastructure d'injection de dépendances est l'une des meilleures solutions de contournement pour cela, et elle résout également de nombreux autres problèmes.
Par Lundberg
5

Il est difficile d'imaginer que cela aurait un effet perceptible sur les performances. Le seul avantage que je peux voir à les faire staticest qu'il fournit une indication visuelle que l'état d'instance n'est pas affecté. En d'autres termes, cela dit à la personne qui lit le code source quelque chose de ... "intéressant" à propos de cette méthode, simplement parce qu'elle est là. La vraie question est: clarifie-t-elle ou confond-elle? "Pourquoi cette méthode est-elle statique? Est-ce une méthode d'usine? La capacité de l'appeler sans instance d'objet est-elle nécessaire?"

De plus, certaines personnes n'aiment pas les méthodes statiques, car elles prétendent que vous ne pouvez pas les moquer, et qu'elles ne sont donc pas testables, ou quelque chose du genre. Certes, si vous le rendez statique pour l'une des raisons habituelles, comme fournir une méthode d'usine par exemple, alors je suis tout à fait d'accord. Je ne suis tout simplement pas sûr que rendre les méthodes statiques simplement parce qu'elles ne touchent pas à l'état d'instance est un mandat.

Robert Harvey
la source
5
Considérez que (dans Java) une méthode statique ne peut pas être remplacée. Bien que cela ne soit pas souvent un problème, cela signifie que certaines sous-classes ne pourront pas modifier cette implémentation ultérieurement. Cela ne veut pas dire qu'une méthode statique n'est pas la bonne réponse mais plutôt une partie des considérations de conception.
2
@ user40980 cela vaut la peine d'être considéré, c'est vrai, mais cela vaut également la peine de considérer que l'héritage peut être un outil maladroit qui est souvent utilisé à mauvais escient, et plusieurs personnalités éminentes soutiennent que toutes les classes devraient être finalou spécifiquement conçues avec l'héritage à l'esprit.
sara
3

Je pense que c'est pour permettre repérer d' .

Une fois que la méthode a été rendue statique, il est clair qu'elle peut être déplacée hors de la classe, disons vers une classe d'unité.

Il est également facile de le transformer en une méthode d'instance de l'un de ses paramètres, c'est souvent là que le code devrait être.

Ian
la source
-1

Notez que vous pouvez avoir des classes sans état qui implémentent une interface (par exemple java.lang.Runnable- vous ne pouvez pas rendre leurs méthodes statiques. Certains modèles (par exemple, la stratégie) peuvent également produire des objets sans état qui peuvent même avoir plusieurs méthodes.

La statique est la cousine germaine des singletons. Il sera très difficile de passer de la statique à la non-statique à un stade ultérieur - donc lorsque vous devrez ajouter un état, vous serez tenté de commencer à introduire des variables statiques.

Eugène
la source
comment cela répond-il à la question posée?
moucher
1
pourquoi est-il difficile de passer d'un état à un autre? Je dirais que c'est l'inverse. il est plus facile de contaminer quelque chose de pur que de purifier quelque chose de contaminé.
sara