L'accès par défaut ne rend pas le modificateur d'accès privé redondant.
La position des concepteurs de langage à ce sujet se reflète dans le tutoriel officiel - Contrôle de l'accès aux membres d'une classe et c'est assez clair (pour votre commodité, la déclaration pertinente dans la citation est mise en gras ):
Conseils sur le choix d'un niveau d'accès:
Si d'autres programmeurs utilisent votre classe, vous voulez vous assurer que les erreurs de mauvaise utilisation ne peuvent pas se produire. Les niveaux d'accès peuvent vous y aider.
- Utilisez le niveau d'accès le plus restrictif qui a du sens pour un membre particulier. Utilisez privé sauf si vous avez une bonne raison de ne pas le faire.
- Évitez les champs publics à l'exception des constantes. (De nombreux exemples du didacticiel utilisent des champs publics. Cela peut aider à illustrer certains points de manière concise, mais n'est pas recommandé pour le code de production.) Les champs publics ont tendance à vous lier à une implémentation particulière et à limiter votre flexibilité dans la modification de votre code.
Votre appel à la testabilité comme justification de la suppression complète du modificateur privé est faux, comme en témoignent par exemple les réponses dans Nouveau dans TDD. Dois-je éviter les méthodes privées maintenant?
Bien sûr, vous pouvez avoir des méthodes privées et bien sûr, vous pouvez les tester.
Soit il y a un moyen de faire fonctionner la méthode privée, auquel cas vous pouvez la tester de cette façon, soit il n'y a aucun moyen de faire exécuter la méthode privée, dans ce cas: pourquoi diable essayez-vous de la tester, juste supprimer la fichue chose ...
La position des concepteurs de langage sur le but et l'utilisation de l'accès au niveau du package est expliquée dans un autre didacticiel officiel, Création et utilisation de packages et il n'a rien en commun avec l'idée de supprimer des modificateurs privés (pour votre commodité, la déclaration pertinente dans la citation est mise en gras ) :
Vous devez regrouper ces classes et l'interface dans un package pour plusieurs raisons, notamment les suivantes:
- Vous et d'autres programmeurs pouvez facilement déterminer que ces types sont liés ...
- Vous pouvez autoriser les types dans le package à avoir un accès illimité les uns aux autres tout en limitant l'accès aux types en dehors du package ...
<rant "Je pense que j'ai entendu assez de gémissements. Je suppose qu'il est temps de dire haut et fort ...">
Les méthodes privées sont avantageuses pour les tests unitaires.
La note ci-dessous suppose que vous connaissez la couverture du code . Sinon, prenez le temps d'apprendre, car il est très utile pour ceux qui s'intéressent aux tests unitaires et aux tests.
Très bien, j'ai donc cette méthode privée et des tests unitaires, et une analyse de couverture me disant qu'il y a un écart, ma méthode privée n'est pas couverte par les tests. À présent...
Qu'est-ce que je gagne à le garder privé
Puisque la méthode est privée, la seule façon de procéder est d'étudier le code pour savoir comment il est utilisé via une API non privée. En règle générale, une telle étude révèle que la raison de l'écart est que le scénario d'utilisation particulier manque dans les tests.
void nonPrivateMethod(boolean condition) {
if (condition) {
privateMethod();
}
// other code...
}
// unit tests don't invoke nonPrivateMethod(true)
// => privateMethod isn't covered.
Dans un souci d'exhaustivité, d'autres raisons (moins fréquentes) pour de telles lacunes de couverture pourraient être des bogues dans la spécification / conception. Je ne vais pas m'y plonger profondément ici, pour garder les choses simples; il suffit de dire que si vous affaiblissez la limitation d'accès "juste pour rendre la méthode testable", vous manquerez une chance d'apprendre que ces bogues existent.
Très bien, pour corriger l'écart, j'ajoute un test unitaire pour le scénario manquant, répète l'analyse de couverture et vérifie que l'écart est disparu. Qu'est-ce que j'ai maintenant? J'ai comme nouveau test unitaire pour une utilisation spécifique de l'API non privée.
Un nouveau test garantit que le comportement attendu pour cette utilisation ne changera pas sans préavis car s'il change, le test échouera.
Un lecteur externe peut examiner ce test et apprendre comment il est censé être utilisé et se comporter (ici, le lecteur externe inclut mon futur moi-même, car j'ai tendance à oublier le code un mois ou deux après en avoir fini).
Un nouveau test est tolérant au refactoring (dois-je refactoriser des méthodes privées? Vous pariez!) Quoi que je fasse privateMethod
, je veux toujours tester nonPrivateMethod(true)
. Peu importe ce que je fais privateMethod
, il ne sera pas nécessaire de modifier le test car la méthode n'est pas directement invoquée.
Pas mal? Tu paries.
Qu'est-ce que je perds de l'affaiblissement de la limitation d'accès
Imaginez maintenant qu'au lieu de ci-dessus, j'affaiblisse simplement la limitation d'accès. Je saute l'étude du code qui utilise la méthode et je continue directement avec le test qui invoque mon exPrivateMethod
. Génial? Ne pas!
Dois-je passer un test pour une utilisation spécifique des API non privées mentionnées ci-dessus? Non: il n'y avait pas de test pour nonPrivateMethod(true)
avant, et il n'y en a plus actuellement.
Les lecteurs externes ont-ils une chance de mieux comprendre l'utilisation de la classe? Non. "- Hé, quel est le but de la méthode testée ici? - Oubliez ça, c'est strictement pour un usage interne. - Oups."
Est-il tolérant au refactoring? Pas question: quoi que je change exPrivateMethod
, cela cassera probablement le test. Renommer, fusionner dans une autre méthode, changer les arguments et tester arrêtera simplement la compilation. Mal de tête? Tu paries!
En résumé , m'en tenir à une méthode privée m'apporte une amélioration utile et fiable dans les tests unitaires. En revanche, l'affaiblissement des limitations d'accès "pour la testabilité" ne me donne qu'un morceau de code de test obscur et difficile à comprendre, qui risque en outre d'être définitivement rompu par une refactorisation mineure; franchement ce que j'obtiens ressemble étrangement à une dette technique .
</rant>