web-dev-qa-db-fra.com

Pourquoi les variables d'instance en Java sont-elles toujours privées?

Je suis un novice en Java et je découvre l'encapsulation. Je vois un exemple où des variables d'instance sont déclarées privées dans une classe. 

http://www.tutorialspoint.com/Java/java_encapsulation.htm

J'ai 2 questions:

  1. Pourquoi les variables d'instance sont-elles privées? Pourquoi pas public?
  2. Que faire si les variables d'instance sont rendues publiques et accessibles directement? Est-ce qu'on voit des contraintes?

Pouvez-vous expliquer avec un exemple ce qui ne va pas se passer si les variables d'instance sont déclarées comme publiques dans une classe en Java? 

20
Deepak

Les variables d'instance sont rendues privées pour forcer les utilisateurs de ces classes à utiliser des méthodes pour y accéder . Dans la plupart des cas, il existe des getters et des setters simples, mais d'autres méthodes peuvent également être utilisées.

L'utilisation de méthodes vous permettrait, par exemple, de limiter l'accès en lecture seule, c'est-à-dire qu'un champ peut être lu mais pas écrit s'il n'y a pas de séparateur. Cela ne serait pas possible si le terrain était public.

En outre, vous pouvez ajouter des vérifications ou des conversions pour l'accès au champ, ce qui ne serait pas possible avec un accès en clair à un champ public. Si un champ est public et que vous souhaitez par la suite forcer tous les accès par une méthode permettant d'effectuer des contrôles supplémentaires, etc., vous devez modifier toutes les utilisations de ce champ. Si vous le rendez privé, il vous suffira de modifier les méthodes d'accès ultérieurement. 

Si phone était privé:

Considérons ce cas:

class Address {
  private String phone;

  public void setPhone(String phone) {
    this.phone = phone;
  }
}

//access:
Address a = new Address();
a.setPhone("001-555-12345");

Si nous commençions avec le cours comme celui-ci et plus tard, il serait nécessaire d'effectuer des vérifications sur le numéro de téléphone (par exemple, une longueur minimale, des chiffres uniquement, etc.), il vous suffirait de changer le sélecteur:

class Address {
  private String phone;

  public void setPhone(String phone) {
    if( !isValid( phone) ) { //the checks are performed in the isValid(...) method
     throw new IllegalArgumentException("please set a valid phone number");
    }

    this.phone = phone;
  }
}

//access:
Address a = new Address();
a.setPhone("001-555-12345"); //access is the same

Si phone était public:

Quelqu'un pourrait définir phone comme ceci et vous ne pouvez rien y faire:

Address a = new Address();
a.phone="001-555-12345";

Si vous voulez maintenant forcer les contrôles de validation à être exécutés, vous devez le rendre privé et quiconque écrit les lignes ci-dessus devra changer la deuxième ligne en ceci:

a.setPhone("001-555-12345");

Ainsi, vous ne pouvez pas simplement ajouter les contrôles sans casser d’autres codes (cela ne compilerait plus).

De plus, si vous accédez à tous les champs/propriétés d'une classe par le biais de méthodes, l'accès est cohérent et l'utilisateur ne doit plus s'inquiéter de savoir si la propriété est stockée (c'est-à-dire un champ d'instance) ou calculée (il n'y a que des méthodes et aucun champ d'instance). ).

35
Thomas

Ils ne doiventpas _ être privés - mais ils devraient l'être. Un champ est un détail d'implémentation - vous devez donc le garder privé. Si vous souhaitez autoriser les utilisateurs à récupérer ou à définir sa valeur, utilisez propriétés pour le faire (méthodes get et set) - cela vous permet de le faire en toute sécurité (par exemple, en validant la saisie) et vous permet également de modifier le paramètre. les détails de la mise en œuvre (par exemple, déléguer certaines des valeurs à d'autres objets, etc.) sans perdre la compatibilité avec les versions antérieures.

10
Jon Skeet

Tout d'abord, il n'est pas vrai que toutes les variables d'instance sont privées. Certains d'entre eux sont protégés, ce qui préserve encore l'encapsulation.

L'idée générale de l'encapsulation est qu'une classe ne doit pas exposer son état interne. Il ne devrait l'utiliser que pour exécuter ses méthodes. La raison en est que chaque classe a un soi-disant "espace d'état". C'est-à-dire un ensemble de valeurs possibles pour ses champs. Il peut contrôler son espace d'état, mais s'il l'expose, d'autres pourraient le placer dans un état invalide.

Par exemple, si vous avez deux champs booléens et que la classe ne peut fonctionner correctement que dans 3 cas: [false, false], [false, true] et [true, false]. Si vous rendez les champs publics, un autre objet peut définir [true, true], sans connaître les contraintes internes, et la méthode suivante appelée sur l'objet d'origine déclenchera des résultats inattendus.

7
Bozho

Rendre les variables d’instance publiques ou privées est un compromis de conception pour le designer fait lors de la déclaration des classes. En faisant exemple variables publiques, vous exposez les détails de l'implémentation de la classe, fournissant ainsi une plus grande efficacité et la concision de l'expression à les dépenses possibles pour entraver les futurs efforts de maintenance. Par masquant les détails de la mise en oeuvre interne d'une classe, vous avez le possibilité de changer la mise en œuvre de la classe à l'avenir sans casser aucun code qui utilise cette classe.

Livre blanc Oracle

4
rwyland

Comme cela a déjà été souligné par plusieurs répondants, les variables d'instance ne doivent pas nécessairement être private, mais elles sont généralement au moins non rendues public, afin de préserver l'encapsulation.

J'ai vu un exemple dans (je pense) Clean Code, qui illustre très bien cela. Si je me souviens bien, c’était un nombre complexe (comme dans a+bi); en tout cas, quelque chose de très semblable, je n'ai pas le livre à portée de main. Il a exposé des méthodes pour obtenir la valeur des parties réelle et imaginaire, ainsi qu'une méthode pour définir la valeur de l'instance. Le gros avantage est que cela permet de remplacer complètement l’implémentation sans casser le consommateur du code. Par exemple, les nombres complexes peuvent être stockés sous l'une des deux formes suivantes: en tant que coordonnées sur le plan complexe (a+bi) ou sous forme polaire (φ et |z|). Conserver le détail de la mise en œuvre dans le format de stockage interne vous permet de changer d'avant en arrière tout en exposant le numéro des deux formulaires, permettant ainsi à l'utilisateur de la classe de choisir celle qui convient le mieux à l'opération en cours.

Dans d'autres situations, vous pouvez avoir un ensemble de champs associés, tel que le champ x doit avoir certaines propriétés si le champ y se situe dans une plage donnée. Un exemple simpliste serait où x doit être compris entre y et y+z, pour les valeurs numériques et certaines valeurs arbitraires z. En exposant des accesseurs et des mutateurs, vous pouvez imposer cette relation entre les deux valeurs; si vous exposez directement les variables d'instance, l'invariant se désagrège immédiatement, car vous ne pouvez pas garantir que quelqu'un ne définira pas l'une mais pas l'autre, ou les définissez de sorte que l'invariant ne soit plus valable.

Bien sûr, en réfléchissant, il est toujours possible d’avoir accès à des membres que vous n’êtes pas censés avoir, mais si quelqu'un réfléchit à votre classe pour accéder à des membres privés, il vaudrait mieux qu'ils se rendent compte que ce qu'ils font peut très bien casser des choses. S'ils utilisent l'interface publique, ils pourraient penser que tout va bien, puis ils se retrouvent avec de vilains bugs, car ils ignoraient, à notre insu, les détails de mise en œuvre de votre implémentation particulière.

2
a CVn

Dans la conception traditionnelle orientée objet, une classe encapsulera à la fois des données (variables) et un comportement (méthodes). Le fait de disposer de données privées vous donnera plus de flexibilité quant à la manière dont le comportement est implémenté. Par exemple, un objet peut stocker une liste de valeurs et disposer d'une méthode getAverage () qui calcule et renvoie la moyenne de ces valeurs. Plus tard, vous pourrez optimiser et mettre en cache la moyenne calculée dans la classe, mais le contrat (c'est-à-dire les méthodes) n'aura pas besoin d'être modifié.

Il est devenu de plus en plus populaire ces dernières années (pour le meilleur ou pour le pire) d’utiliser des modèles de données anémiques , où une classe n’est qu’un ensemble de domaines et d’objets correspondants. Je dirais que dans cette conception, vous seriez mieux avec des champs publics, puisque les accesseurs et les setters ne fournissent aucune encapsulation réelle, mais vous trompent en leur faisant croire que vous faites de véritables OO.

UPDATE: L'exemple donné dans le lien de la question est un exemple parfait de cette encapsulation dégénérée. Je me rends compte que l'auteur essaie de donner un exemple simple, mais ce faisant, il ne présente aucun avantage réel de l'encapsulation (du moins pas dans l'exemple de code).

1
James Scriven

Pour utilisateur de classe

Nous, qui utilisons ide comme Eclipse, netbins ..... Nous avons vu qu'elle nous suggère une méthode publique. Par conséquent, si le créateur de la classe fournit des variables getter et setter pour des variables d'instance privées, vous n'avez pas à mémoriser le nom de la variable. . il suffit d'écrire set, appuyez sur ctrl + espace, vous obtenez toutes les méthodes de définition créées par le créateur de cette classe et choisissez la méthode de votre choix pour définir la valeur de votre variable.

Pour créateur de classe

Parfois, vous devez spécifier une logique pour définir la valeur de la variable . "Supposons que vous ayez une variable entière devant stocker 0

0
  1. Parce que si vous modifiez la structure de la classe (suppression des champs, etc.); cela causera des bugs. Mais si vous avez une méthode getX(), vous pouvez y calculer la valeur nécessaire (si le champ a été supprimé).

  2. Vous avez le problème alors que la classe ne sait pas si quelque chose a changé et ne peut pas garantir l'intégrité.

0
MasterCassim

Bien garder les champs privés présente de nombreux avantages, comme suggéré ci-dessus ... Le niveau suivant consiste à les garder privés en utilisant le niveau d'accès par défaut Java.

Le niveau par défaut évite d'encombrer votre propre code et empêche les clients de votre code de définir des valeurs non valides.

0
Mangoose