Je pose cette question parce que je pense qu'ils l'ont fait pour une très bonne raison et que la plupart des gens ne l'utilisent pas correctement, d'après mon expérience dans l'industrie jusqu'à présent de toute façon. Mais si ma théorie est vraie, je ne sais pas pourquoi ils ont inclus le modificateur d'accès privé ...?
Je crois que si l'accès par défaut est correctement utilisé, il offre une testabilité améliorée tout en maintenant l'encapsulation. Et il rend également le modificateur d'accès privé redondant.
Le modificateur d'accès par défaut peut être utilisé pour fournir le même effet en utilisant un package unique pour les méthodes qui doivent être cachées du reste du monde, et il le fait sans compromettre la testabilité, car les packages dans un dossier de test, avec le même sont capable d'accéder à toutes les méthodes par défaut déclarées dans un dossier source.
Je pense que c'est la raison pour laquelle Java utilise l'accès aux packages comme «par défaut». Mais je ne sais pas pourquoi ils ont également inclus un accès privé, je suis sûr qu'il existe un cas d'utilisation valide ...
Réponses:
Je suppose qu'ils avaient une bonne idée de ce qu'un programmeur moyen ferait. Et par programmeur moyen, je veux dire celui qui n'est pas vraiment bon en programmation, mais qui réussit quand même parce qu'il n'y en a pas assez et qu'ils sont chers.
S'ils rendaient l'accès "public" par défaut, la plupart des programmeurs ne prendraient jamais la peine d'utiliser autre chose. Le résultat serait beaucoup de code spaghetti partout. (Parce que si vous êtes techniquement autorisé à appeler n'importe quoi de n'importe où, pourquoi vous embêter à encapsuler une logique dans une méthode?)
Rendre "privé" l'accès par défaut ne serait que légèrement meilleur. La plupart des programmeurs débutants inventeraient simplement (et partageraient sur leurs blogs) une règle empirique selon laquelle "vous devez écrire" public "partout", puis ils se plaindraient pourquoi Java est si mauvais qu'il les oblige à écrire "public" partout. Et ils produiraient également beaucoup de code spaghetti.
L'accès aux packages est quelque chose qui permet aux programmeurs d'utiliser leurs techniques de programmation bâclées lors de l'écriture de code dans un package, mais ils doivent ensuite le reconsidérer lors de la création de plusieurs packages. Il s'agit d'un compromis entre les bonnes pratiques commerciales et la réalité laide. Comme: écrivez du code spaghetti, si vous insistez, mais veuillez laisser le désordre laid dans le paquet; au moins créer des interfaces plus agréables parmi les packages.
Il y a probablement d'autres raisons aussi, mais je ne sous-estimerais pas celle-ci.
la source
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 ):
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?
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 ) :
<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.
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 testernonPrivateMethod(true)
. Peu importe ce que je faisprivateMethod
, 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>
la source
La raison la plus probable est: cela a à voir avec l'histoire. L'ancêtre de Java, Oak, n'avait que trois niveaux d'accès: privé, protégé, public.
Sauf que private dans Oak était l'équivalent du package private dans Java. Vous pouvez lire la section 4.10 de la spécification de langue d' Oak (c'est moi qui souligne):
Donc à votre point, l'accès privé, comme connu en Java, n'était pas là à l'origine. Mais lorsque vous avez plus de quelques classes dans un package, ne pas avoir privé comme nous le savons maintenant conduirait à un cauchemar de collision de noms (par exemple, java.until.concurrent a près de 60 classes), c'est probablement pourquoi ils l'a présenté.
Cependant, la sémantique d'accès au package par défaut (initialement appelée privée) n'a pas été modifiée entre Oak et Java.
la source
Il y a des situations où l'on voudrait deux classes distinctes qui sont plus étroitement liées que de tout exposer au public. Cela a des idées similaires d '«amis» en C ++ où une autre classe qui est déclarée «amie» d'une autre peut accéder à ses membres privés.
Si vous regardez dans les entrailles de classes telles que BigInteger, vous trouverez un certain nombre de protections par défaut des packages sur les champs et les méthodes (tout ce qui est un triangle bleu dans la liste). Cela permet aux autres classes du package java.math d'avoir un accès plus optimal à leurs entrailles pour des opérations spécifiques (vous pouvez trouver ces méthodes appelées dans BigDecimal - BigDecimal est soutenu par un BigInteger et évite de réimplémenter BigInteger à nouveau . t un problème de protection car java.math est un package scellé et aucune autre classe ne peut y être ajoutée.
D'un autre côté, il y a beaucoup de choses qui sont en effet privées, comme elles devraient l'être. La plupart des colis ne sont pas scellés. Sans privé, votre collègue pourrait mettre une autre classe dans ce package et accéder au champ (plus) privé et rompre l'encapsulation.
Il convient de noter que les tests unitaires n'étaient pas une chose à laquelle on pensait à l'époque de la construction des étendues de protection. JUnit (le framework de test XUnit pour Java) n'a été conçu qu'en 1997 (un récit de cette histoire peut être lu sur http://www.martinfowler.com/bliki/Xunit.html ). Les versions Alpha et Beta du JDK étaient en 1995 et JDK 1.0 en 1996, bien que les niveaux de protection n'aient pas vraiment été cloués avant JDK 1.0.2 (avant cela, vous pouviez avoir un
private protected
niveau de protection).Certains diront que la valeur par défaut ne devrait pas être au niveau du package, mais privée. D'autres soutiennent qu'il ne devrait pas y avoir de protection par défaut mais tout devrait être explicitement déclaré - certains adeptes de cela écriront du code tel que:
Notez le commentaire ici.
La vraie raison pour laquelle la protection au niveau du package est la valeur par défaut est probablement perdue dans les notes de conception de Java (j'ai creusé et je ne trouve pas pourquoi les articles, beaucoup de gens expliquent la différence, mais aucun ne dit "c'est la raison ").
Je vais donc deviner. Et c'est tout ce que c'est - une supposition.
Tout d'abord, les gens essayaient toujours de comprendre la conception du langage. Depuis lors, les langues ont appris des erreurs et des succès de Java. Cela pourrait être répertorié comme une erreur de ne pas avoir quelque chose qui doit être défini pour tous les champs.
public
, etprivate
comme celles-ci ont les plus grands impacts sur l'accès.Ainsi, privé n'est pas par défaut et bien, tout le reste s'est mis en place. La portée par défaut a été laissée par défaut. C'est peut -être la première portée qui a été créée et dans l'intérêt d'une compatibilité ascendante rigoureuse avec le code plus ancien, elle a été laissée de cette façon.
Comme je l'ai dit, tout cela n'est qu'une supposition .
la source
L'encapsulation est une façon de dire "vous n'avez pas à y penser".
Mettre ces termes en termes non techniques.
la source
Je ne pense pas qu'ils se soient concentrés sur les tests, simplement parce que les tests n'étaient pas très courants à l'époque.
Ce que je pense qu'ils voulaient réaliser, c'était l'encapsulation au niveau du package. Une classe peut, comme vous le savez, avoir des méthodes et des champs internes et n'en exposer qu'une partie par le biais de membres publics. De la même manière, un package peut avoir des classes, des méthodes et des champs internes et n'en exposer qu'une partie. Si vous pensez de cette façon, un package a une implémentation interne dans un ensemble de classes, méthodes et champs, ainsi qu'une interface publique dans un autre ensemble (éventuellement se chevauchant partiellement) de classes, méthodes et champs.
Les codeurs les plus expérimentés que je connais pensent de cette façon. Ils prennent l'encapsulation et l'appliquent à un niveau d'abstraction supérieur à la classe: un package ou un composant si vous le souhaitez. Il me semble raisonnable que les concepteurs de Java soient déjà aussi matures dans leurs conceptions, compte tenu de la résistance de Java.
la source