Pourquoi un membre privé est-il accessible dans une méthode statique?

25

Ce qui suit est du pseudo code, je l'ai essayé en Java et PHP et les deux ont fonctionné:

class Test { 

    private int a = 5;

    public static function do_test(){
        var t = new Test();
        t.a = 1;
        print t.a // 1
    }

}

Test::do_test();

Pourquoi pouvez-vous faire cela dans le paradigme OOP et à quoi cela sert-il?

Ben
la source
6
Pourquoi ne serait-ce pas? En Java, les membres privés ne sont pas privés pour l'instance, mais plutôt privés pour le fichier source . La première utilisation qui me vient à l'esprit est de equalsdevoir vérifier les champs privés d'une autre instance. (Publication sous forme de commentaire, car cela est court, et rien sur la POO de cette approche)
Ordous
2
Notez que les méthodes statiques n'en ont pas this, donc les seuls objets de leur propre classe auxquels ils peuvent accéder sont ceux qu'ils créent eux-mêmes (ou qui sont passés en tant que paramètre). Donc, si vous considérez cela comme une violation de l'encapsulation ou une faille de sécurité, ce n'est pas comme si c'était un très gros, et cela ne vaut peut-être pas la peine d'être branché.
Kilian Foth du
4
Je ne sais pas pourquoi cela a été rejeté. La question peut être triviale (ish), mais l'OP a eu la peine de tester le comportement dans deux langues avant de se poser. C'est beaucoup plus d'efforts que ce que nous voyons habituellement des nouveaux arrivants.
yannis
1
@YannisRizos D'accord, et en fait je ne pense pas que la question soit triviale. Elle a des implications pour le respect du "principe du moindre privilège". Cela signifie que les fonctions d'assistance qui n'ont pas besoin d'accéder aux éléments internes d'une instance doivent être définies dans une classe distincte , et inversement, lorsque cette convention est suivie, vous savez que chaque fois qu'une méthode statique existe dans la même classe, elle accède à l'état interne.
Doval
1
En fait, quand j'ai demandé à mes collègues, tous ont dit que c'était impossible. C'est pourquoi je ne pensais pas que c'était trivial
Ben

Réponses:

17

En Java, les variables privées sont visibles pour toute la classe. Ils sont accessibles à partir de méthodes statiques et d'autres instances de la même classe.

C'est, par exemple, utile dans les méthodes d'usine . Une méthode d'usine fait généralement des initialisations à un objet qui sont si complexes que vous ne voulez pas les laisser au code d'application. Pour effectuer l'initialisation, la méthode d'usine a souvent besoin d'accéder aux internes de classe que vous ne souhaitez pas exposer. Pouvoir accéder directement aux variables privées vous facilite la vie.

Cependant, lorsque vous souhaitez masquer les détails d'implémentation d'une classe même à partir de méthodes statiques ou d'autres instances de cette classe, vous pouvez suivre le modèle de données de classe privée . Mettez toutes les variables privées d'une classe dans une classe interne privée et déléguez les getters ou setters aux getters et setters de cette classe interne.

Une autre option consiste à définir une interface pour la classe qui déclare toutes les méthodes publiques de la classe et à ne référencer la classe sous cette interface que dans la mesure du possible. Une référence au type d'interface ne peut pas être utilisée pour accéder directement à tout ce qui n'est pas déclaré dans l'interface, peu importe où (sauf avec réflexion, bien sûr). Lorsque vous utilisez un langage de programmation orienté objet qui n'a pas d'interfaces (comme C ++, par exemple), ils peuvent être simulés avec une classe de base abstraite héritée par la classe réelle.

interface ITest {
     public int getA();
}

class Test implements ITest { 

    private int a = 5;

    public int getA() { return a; } // implementation of method declared in interface

    public static void main(){
        ITest t = new Test();
        t.a = 1; // syntax error: Interface ITest has no "a"
        System.out.println(t.getA()); // calls Test.getA, visible because ITest declares it
    }

}
Philipp
la source
Pouvez-vous penser à une situation où le modèle de données de classe privée est utile? Personnellement, j'utilise des classes internes uniquement dans des configurations graphiques (comme Swing, etc.) ou des classes internes statiques dans les exercices de codage, car je ne veux pas qu'un exercice s'étende sur plusieurs fichiers source.
InformedA
1
Masquer les éléments internes d'une classe à d' autres instances enlève l'un des avantages des classes sur les interfaces sans rien récupérer en échange. Une solution plus simple et plus flexible consiste simplement à utiliser une interface.
Doval
3

Certains langages et frameworks d'exécution (par exemple Java, .NET) supposent que toute personne qui compile le code pour une classe particulière peut être autorisée à ne pas utiliser les membres privés d'une instance de cette classe d'une manière qui serait préjudiciable à son correct opération. D'autres langages et frameworks sont plus restrictifs à cet égard et n'autorisent pas l'accès aux membres privés d'une instance, sauf par le code exécuté sur cette instance . Les deux conceptions présentent des avantages et des inconvénients.

Le plus grand avantage de permettre à n'importe quel code d'une classe d'accéder aux membres privés de n'importe quelle instance est qu'il existe des cas où ce niveau d'accès est approprié, et le fait de privatetravailler de cette façon élimine la nécessité d'avoir un qualificatif d'accès différent disponible à cet effet ou sinon forcer le code à exposer les membres plus largement que ce ne serait autrement l'idéal.

Un avantage de l'interdiction de cet accès (comme c'était le cas dans le Microsoft Common Object Model (COM)) est qu'il permet au code extérieur de traiter les classes comme des interfaces. Si une classe ImmutableMatrixcontient un double[][]champ de sauvegarde privé ou protégé , et si le code dans la classe examine le tableau de sauvegarde d'autres instances, il ne sera pas possible de définir une classe non soutenue par un tableau (par exemple ZeroMatrix, IdentityMatrix) que le code extérieur pourrait utiliser comme an Immutable2dMatrix, sans que cette classe doive inclure le champ de support. Si rien à l'intérieur Immutable2dMatrixn'utilise des membres privés d'une instance autre que this, alors il serait possible de renommer la classe ImmutableArrayBackedMatrixet de définir une nouvelle ImmutableMatrixclasse abstraite qui pourrait avoir ImmutableArrayBackedMatrixaussi bien que les classes susmentionnées non soutenues par un tableau comme sous-types.

Notez que ce refactoring ne serait pas empêché par le fait que le langage "autorise" ImmutableMatrixà examiner le tableau de support pour des instances autres que this, à moins que le langage ne profite de cette capacité et n'examine réellement des instances externes. Le principal effet d'un langage restreignant une telle utilisation est qu'il fera immédiatement grincer le compilateur à toute tentative d'écriture de code qui ne se prêterait pas à une telle refactorisation.

supercat
la source
2

Java n'est pas strictement un langage orienté objet, mais un langage basé sur une classe - la classe détermine les opérations et l'accès au comportement plutôt que l'instance.

Ne soyez donc pas trop surpris qu'il vous permette de faire des choses qui ne sont pas strictement orientées objet.

Étant donné que la méthode est dans la même portée de classe que l'instance, elle a un accès complet aux membres privés. Des règles similaires régissent les instances de classes internes accédant aux données à partir d'instances de classes externes - une instance d'une classe interne peut accéder aux membres privés de la classe externe.

Ceci est hérité de C ++, où il est utile pour créer des constructeurs de copie et de déplacement. Il est également utile pour comparer ou combiner deux objets lorsque leur valeur dépend de membres qui ne sont pas accessibles au public de manière efficace (par exemple, le getter pour un tableau en Java doit copier le tableau afin que le code client ne puisse pas le modifier, en changeant l'état interne de l'objet, mais avoir à copier des tableaux pour comparer l'égalité des objets n'est pas efficace)

Pete Kirkham
la source