la recherche d'un cas d'utilisation spécifique où une sous-classe et une classe dans le même package doivent accéder à un champ ou une méthode protégée ...
Eh bien pour moi, un tel cas d'utilisation est plutôt général que spécifique, et il découle de mes préférences pour:
- Commencez avec un modificateur d'accès aussi strict que possible, en ne recourant à un ou plusieurs plus faibles que plus tard, si cela est jugé nécessaire.
- Faites en sorte que les tests unitaires résident dans le même package que le code testé.
D'en haut, je peux commencer à concevoir pour mes objets avec des modificateurs d'accès par défaut (je commencerais par private
mais cela compliquerait les tests unitaires):
public class Example {
public static void main(String [] args) {
new UnitTest().testDoSomething(new Unit1(), new Unit2());
}
static class Unit1 {
void doSomething() {} // default access
}
static class Unit2 {
void doSomething() {} // default access
}
static class UnitTest {
void testDoSomething(Unit1 unit1, Unit2 unit2) {
unit1.doSomething();
unit2.doSomething();
}
}
}
Note latérale dans l'extrait ci-dessus Unit1
, Unit2
et UnitTest
sont imbriqués dans Example
un souci de simplicité de présentation, mais dans un projet réel, j'aurais probablement ces classes dans des fichiers séparés (et UnitTest
même dans un répertoire séparé ).
Ensuite, lorsqu'une nécessité survient, j'affaiblirais le contrôle d'accès par défaut à protected
:
public class ExampleEvolved {
public static void main(String [] args) {
new UnitTest().testDoSomething(new Unit1(), new Unit2());
}
static class Unit1 {
protected void doSomething() {} // made protected
}
static class Unit2 {
protected void doSomething() {} // made protected
}
static class UnitTest {
// ---> no changes needed although UnitTest doesn't subclass
// ...and, hey, if I'd have to subclass... which one of Unit1, Unit2?
void testDoSomething(Unit1 unit1, Unit2 unit2) {
unit1.doSomething();
unit2.doSomething();
}
}
}
Vous voyez, je peux garder le code de test unitaire ExampleEvolved
inchangé car les méthodes protégées sont accessibles à partir du même package, même si l'accès à l'objet n'est pas une sous-classe .
Moins de changements nécessaires => modification plus sûre; après tout, je n'ai changé que les modificateurs d'accès et je n'ai pas modifié les méthodes Unit1.doSomething()
et les Unit2.doSomething()
actions, il est donc naturel de s'attendre à ce que le code de test unitaire continue de s'exécuter sans modifications.
protected
sous-classe est uniquement? Honnêtement, pendant longtemps, j'avais l'impression queprotected
est classe et sous - classe uniquement, etinternal
est une bibliothèque / package à l' échelle. Il a égalementprotected internal
l'équivalent de Javaprotected
.À mon humble avis, c'était une mauvaise décision de conception en Java.
Je ne fais que spéculer, mais je pense qu'ils voulaient que les niveaux d'accès soient dans une stricte progression: privé - "package" - protégé - public. Ils ne voulaient pas avoir une hiérarchie, où certains champs seraient disponibles pour le package mais pas les sous-classes, certains disponibles pour les sous-classes mais pas le package, et certains les deux.
Pourtant, à mon humble avis, ils auraient dû aller dans l'autre sens: a déclaré que protégé est visible uniquement pour la classe et les sous-classes, et que le package est visible pour la classe, les sous-classes et le package.
J'ai souvent des données dans une classe qui doivent être accessibles aux sous-classes, mais pas au reste du package. J'ai du mal à penser à un cas où l'inverse était vrai. J'ai eu quelques rares occasions où j'ai eu un ensemble de classes interdépendantes qui ont besoin de partager des données mais qui devraient garder ces données à l'abri de l'extérieur de l'ensemble. Alors d'accord, mettez-les dans un paquet, etc. Mais je n'ai jamais eu de cas où je veux que le paquet partage des données, mais je veux le garder des sous-classes. D'accord, je peux imaginer la situation à venir. Je suppose que si ce paquet fait partie d'une bibliothèque qui pourrait être étendue par des classes, je ne sais rien, pour les mêmes raisons que je rendrais les données d'une classe privées. Mais il est beaucoup plus courant de vouloir rendre les données disponibles uniquement pour la classe et ses enfants.
Il y a beaucoup de choses que je garde secrètes entre moi et mes enfants et nous ne partageons pas avec les voisins. Il y a très peu de choses que je garde privées entre moi et les voisins et que je ne partage pas avec mes enfants. :-)
la source
Un bon exemple qui vient immédiatement à l'esprit est les classes d'utilitaires qui sont beaucoup utilisées dans le package, mais vous ne voulez pas d'accès public (les coulisses-chargement d'image à partir du disque, les classes de création / destruction de descripteurs, etc. .) au lieu de tout faire [l'équivalent de Java
friend access modifier or idiom
dansC++
] de toutes les autres classes, tout est automatiquement disponible.la source
Les cas d'utilisation du modificateur d'accès protégé / package sont similaires à ceux des modificateurs d'accès ami en C ++.
Un cas d'utilisation est lors de l'implémentation du modèle Memento .
L'objet memento doit accéder à l'état interne d'un objet, le conserver, afin de servir de point de contrôle pour les opérations d'annulation.
Déclarer la classe dans le même package est l' un des moyens possibles pour réaliser le modèle Memento, car Java n'a pas de modificateur d'accès "ami" .
la source
symétrie?
Il est rare d'avoir besoin d'un tel accès, c'est pourquoi l'accès par défaut est si rarement utilisé. Mais parfois, les frameworks le souhaitent pour le code généré, où les classes wrapper sont placées dans le même package qui interagissent directement avec vos classes, allant aux membres plutôt qu'aux accesseurs pour des raisons de performances. Pensez GWT.
la source
La hiérarchie d'encapsulation de Java est bien définie:
Classe -> Package -> Héritage
"Protégé" est juste une forme de confidentialité plus faible que le package-default comme décidé par les concepteurs Java. L'accès aux éléments par défaut du package est limité à un sous-ensemble des entités autorisées à accéder aux éléments protégés.
D'un point de vue mathématique et d'implémentation, il est très logique d'avoir vos ensembles d'entités autorisés à accéder aux éléments à imbriquer. (Vous ne pouviez pas imbriquer votre ensemble d'accès au package dans votre ensemble d'accès protégé car les classes sont autorisées à hériter d'autres packages).
D'un point de vue conceptuel, il est logique d'avoir quelque chose dans java.util pour être "plus convivial" avec une autre classe dans le package que quelque chose dans com.example.foo.bar qui le sous-classe. Dans le premier cas, les cours sont susceptibles d'être écrits par le même auteur, ou au moins des codeurs de la même organisation.
la source