Est-ce complètement contraire à la manière Java de créer des objets de structure?
class SomeData1 {
public int x;
public int y;
}
Je peux voir une classe avec des accesseurs et des mutateurs ressemblant plus à Java.
class SomeData2 {
int getX();
void setX(int x);
int getY();
void setY(int y);
private int x;
private int y;
}
La classe du premier exemple est pratique sur le plan de la notation.
// a function in a class
public int f(SomeData1 d) {
return (3 * d.x) / d.y;
}
Ce n'est pas aussi pratique.
// a function in a class
public int f(SomeData2 d) {
return (3 * d.getX()) / d.getY();
}
Réponses:
Il s'agit d'un sujet fréquemment discuté. L'inconvénient de créer des champs publics dans des objets est que vous n'avez aucun contrôle sur les valeurs qui lui sont définies. Dans les projets de groupe où de nombreux programmeurs utilisent le même code, il est important d'éviter les effets secondaires. En outre, il est parfois préférable de renvoyer une copie de l'objet du champ ou de le transformer d'une manière ou d'une autre, etc. Vous pouvez vous moquer de ces méthodes dans vos tests. Si vous créez une nouvelle classe, vous ne verrez peut-être pas toutes les actions possibles. C'est comme une programmation défensive - un jour, les getters et setters peuvent être utiles, et leur création / utilisation ne coûte pas cher. Ils sont donc parfois utiles.
En pratique, la plupart des domaines ont de simples getters et setters. Une solution possible ressemblerait à ceci:
Mise à jour: Il est très peu probable que la prise en charge des propriétés soit ajoutée dans Java 7 ou peut-être jamais. D'autres langages JVM comme Groovy, Scala, etc. prennent désormais en charge cette fonctionnalité. - Alex Miller
la source
=
, ce qui à mon avis rend le code plus propre.x
n'est pas parce que vous POUVEZ avoir deux s qui sont deux choses différentes que ce n'est pas une bonne idée. À mon humble avis, c'est une mauvaise suggestion, car elle pourrait entraîner la confusion chez les lecteurs humains. Principe de base: ne pas obliger un lecteur à faire une double prise; rendre évident ce que vous dites - Utilisez des noms différents pour différentes entités. Même si la différence consiste simplement à ajouter un trait de soulignement. Ne vous fiez pas à la ponctuation environnante pour différencier les entités.Il semble que de nombreuses personnes Java ne connaissent pas les Sun Java Coding Guidelines qui disent qu'il est tout à fait approprié d'utiliser une variable d'instance publique lorsque la classe est essentiellement une "Struct", si Java prend en charge la "struct" (lorsqu'il n'y a pas de comportement).
Les gens ont tendance à penser que les getters et setters sont la voie Java, comme s'ils étaient au cœur de Java. Ce n'est pas le cas. Si vous suivez les directives de codage Sun Java, en utilisant des variables d'instance publique dans des situations appropriées, vous écrivez en fait un meilleur code que l'encombrer avec des getters et setters inutiles.
Conventions de code Java de 1999 et toujours inchangées.
10.1 Fournir l'accès aux variables d'instance et de classe
Ne rendez aucune variable d'instance ou de classe publique sans raison valable. Souvent, les variables d'instance n'ont pas besoin d'être explicitement définies ou obtenues, ce qui se produit comme effet secondaire des appels de méthode.
Un exemple de variables d'instance publique appropriées est le cas où la classe est essentiellement une structure de données, sans comportement. En d'autres termes, si vous auriez utilisé une structure au lieu d'une classe (si la structure est prise en charge par Java), il est approprié de rendre publiques les variables d'instance de la classe .
http://www.oracle.com/technetwork/java/javase/documentation/codeconventions-137265.html#177
http://en.wikipedia.org/wiki/Plain_old_data_structure
http://docs.oracle.com/javase/1.3/docs/guide/collections/designfaq.html#28
la source
Utilisez vraiment le bon sens. Si vous avez quelque chose comme:
Ensuite, il ne sert à rien de les envelopper dans des getters et des setters. Vous n'allez jamais stocker une coordonnée x, y en pixels entiers d'une autre manière. Les getters et setters ne feront que vous ralentir.
D'autre part, avec:
Vous voudrez peut-être modifier la façon dont un solde est calculé à un moment donné dans le futur. Cela devrait vraiment utiliser des getters et setters.
Il est toujours préférable de savoir pourquoi vous appliquez les bonnes pratiques, afin de savoir quand vous pouvez contourner les règles.
la source
(-5, -5)
pourrait ne pas être une bonne idée. :-)Pour résoudre les problèmes de mutabilité, vous pouvez déclarer x et y comme définitifs. Par exemple:
L'appel de code qui tente d'écrire dans ces champs obtiendra une erreur de temps de compilation de "le champ x est déclaré final; ne peut pas être attribué".
Le code client peut alors avoir la commodité «abrégée» que vous avez décrite dans votre message
la source
case
expression faisant référence à un tel champ d'instance, j'ai réussiCase expressions must be constant expressions
. quelle est la solution? quel est le concept idiomatique ici?N'utilisez pas de
public
champsN'utilisez pas de
public
champs lorsque vous voulez vraiment envelopper le comportement interne d'une classe. Prenezjava.io.BufferedReader
par exemple. Il a le champ suivant:skipLF
est lu et écrit dans toutes les méthodes de lecture. Que se passe-t-il si une classe externe exécutée dans un thread séparé modifie par malveillance l'état deskipLF
au milieu d'une lecture?BufferedReader
ira certainement détraqué.Utilisez des
public
champsPrenez ce
Point
cours par exemple:Cela rendrait le calcul de la distance entre deux points très pénible à écrire.
La classe n'a aucun comportement autre que les getters et les setters. Il est acceptable d'utiliser des champs publics lorsque la classe ne représente qu'une structure de données et n'a pas, et n'aura jamais de comportement (les getters et setters fins ne sont pas considérés comme des comportements ici). Il peut être mieux écrit de cette façon:
Nettoyer!
Mais rappelez-vous: non seulement votre classe ne doit pas avoir de comportement, mais elle ne devrait pas non plus avoir de raison d'avoir un comportement à l'avenir également.
(C'est exactement ce que cette réponse décrit. Pour citer "Conventions de code pour le langage de programmation Java: 10. Pratiques de programmation" :
La documentation officielle accepte donc également cette pratique.)
De plus, si vous êtes très sûr que les membres de la
Point
classe ci - dessus doivent être immuables, vous pouvez ajouter unfinal
mot clé pour l'appliquer:la source
Soit dit en passant, la structure que vous donnez comme exemple existe déjà dans la bibliothèque de classes de base Java en tant que
java.awt.Point
. Il a x et y comme champs publics, vérifiez par vous-même .Si vous savez ce que vous faites et que d'autres membres de votre équipe le savent, il est normal d'avoir des champs publics. Mais vous ne devriez pas vous y fier car ils peuvent provoquer des maux de tête comme dans les bogues liés aux développeurs utilisant des objets comme s'ils étaient des structures allouées par pile (les objets java sont toujours envoyés aux méthodes en tant que références et non pas en tant que copies).
la source
public final
champ, comme dans la réponse de Brian, ou en ayant un getter public, mais pas de setter public. Autrement dit, que l'on utilise des champs ou des accesseurs est sans importance.Re: aku, izb, John Topley ...
Attention aux problèmes de mutabilité ...
Il peut sembler judicieux d'omettre les getters / setters. En fait, cela peut être correct dans certains cas. Le vrai problème avec le modèle proposé ici est la mutabilité.
Le problème est une fois que vous passez une référence d'objet contenant des champs publics non finaux. Tout autre élément avec cette référence est libre de modifier ces champs. Vous n'avez plus aucun contrôle sur l'état de cet objet. (Pensez à ce qui se passerait si les cordes étaient mutables.)
Cela devient mauvais lorsque cet objet est une partie importante de l'état interne d'un autre, vous venez de révéler l'implémentation interne. Pour éviter cela, une copie de l'objet doit être retournée à la place. Cela fonctionne, mais peut entraîner une pression massive du GC à partir de tonnes de copies à usage unique créées.
Si vous avez des champs publics, pensez à rendre la classe en lecture seule. Ajoutez les champs en tant que paramètres au constructeur et marquez les champs comme définitifs. Sinon, assurez-vous que vous n'exposez pas l'état interne, et si vous devez construire de nouvelles instances pour une valeur de retour, assurez-vous qu'elle ne sera pas appelée de manière excessive.
Voir: " Java efficace " par Joshua Bloch - Article # 13: Favoriser l'immuabilité.
PS: Gardez également à l'esprit que toutes les machines virtuelles Java de nos jours optimiseront la méthode getMethod si possible, résultant en une seule instruction de lecture sur le terrain.
la source
J'ai essayé cela dans quelques projets, sur la théorie selon laquelle les getters et les setters encombrent le code avec une cruauté sémantiquement dénuée de sens, et que d'autres langages semblent faire très bien avec le masquage de données basé sur les conventions ou le partitionnement des responsabilités (par exemple python).
Comme d'autres l'ont noté ci-dessus, vous rencontrez 2 problèmes et ils ne sont pas vraiment réparables:
Et c'est dans le meilleur des cas de travailler entièrement dans un projet privé autonome. Une fois que vous aurez exporté le tout dans une bibliothèque accessible au public, ces problèmes deviendront encore plus importants.
Java est très verbeux, et c'est une chose tentante à faire. Ne le fais pas.
la source
Si la voie Java est la voie OO, alors oui, la création d'une classe avec des champs publics rompt les principes de masquage des informations qui disent qu'un objet doit gérer son propre état interne. (Donc, comme je ne vous jette pas seulement du jargon, un avantage de la dissimulation d'informations est que le fonctionnement interne d'une classe est caché derrière une interface - disons que vous vouliez changer le mécanisme par lequel votre classe struct a enregistré l'un de ses champs, vous devrez probablement revenir en arrière et modifier toutes les classes qui utilisent la classe ...)
Vous ne pouvez pas non plus tirer parti de la prise en charge des classes compatibles avec la dénomination JavaBean, ce qui sera nuisible si vous décidez, par exemple, d'utiliser la classe dans une page JavaServer écrite à l'aide du langage d'expression.
L'article JavaWorld Why Getter and Setter Methods are Evil article pourrait également vous intéresser pour savoir quand ne pas implémenter les méthodes d'accesseur et de mutateur.
Si vous écrivez une petite solution et que vous souhaitez minimiser la quantité de code impliqué, la méthode Java n'est peut-être pas la bonne - je suppose que cela dépend toujours de vous et du problème que vous essayez de résoudre.
la source
Il n'y a rien de mal à ce type de code, à condition que l'auteur sache qu'il s'agit de structures (ou navettes de données) au lieu d'objets. De nombreux développeurs Java ne peuvent pas faire la différence entre un objet bien formé (pas seulement une sous-classe de java.lang.Object, mais un véritable objet dans un domaine spécifique) et un ananas. Ergo, ils finissent par écrire des structures quand ils ont besoin d'objets et vice-versa.
la source
Le problème avec l'utilisation de l'accès au champ public est le même problème que l'utilisation de new au lieu d'une méthode d'usine - si vous changez d'avis plus tard, tous les appelants existants sont interrompus. Donc, du point de vue de l'évolution de l'API, c'est généralement une bonne idée de mordre la balle et d'utiliser des getters / setters.
Un endroit où je vais dans l'autre sens est lorsque vous contrôlez fortement l'accès à la classe, par exemple dans une classe statique interne utilisée comme structure de données interne. Dans ce cas, il pourrait être beaucoup plus clair d'utiliser l'accès aux champs.
Soit dit en passant, selon l'affirmation d'e-bartek, il est hautement improbable que l'OMI ajoute la prise en charge des propriétés dans Java 7.
la source
J'utilise fréquemment ce modèle lors de la création de classes internes privées pour simplifier mon code, mais je ne recommanderais pas d'exposer de tels objets dans une API publique. En général, plus vous pouvez rendre immuables les objets de votre API publique, mieux c'est, et il n'est pas possible de construire votre objet "struct-like" de manière immuable.
En passant, même si j'écrivais cet objet en tant que classe interne privée, je fournirais toujours un constructeur pour simplifier le code pour initialiser l'objet. Devoir avoir 3 lignes de code pour obtenir un objet utilisable quand on le fera est juste désordonné.
la source
Une question très très ancienne, mais permettez-moi de faire une autre brève contribution. Java 8 a introduit des expressions lambda et des références de méthode. Les expressions lambda peuvent être de simples références de méthode et ne pas déclarer un "vrai" corps. Mais vous ne pouvez pas "convertir" un champ en référence de méthode. Donc
n'est pas légal, mais
est.
la source
data -> data.x
, ce qui est toujours raisonnableJe ne vois pas le mal si vous savez que ce sera toujours une structure simple et que vous ne voudrez jamais y attacher de comportement.
la source
C'est une question sur la conception orientée objet, pas Java le langage. Il est généralement recommandé de masquer les types de données dans la classe et d'exposer uniquement les méthodes qui font partie de l'API de classe. Si vous exposez des types de données internes, vous ne pourrez jamais les modifier à l'avenir. Si vous les masquez, votre seule obligation envers l'utilisateur est le type de retour et d'argument de la méthode.
la source
Ici, je crée un programme pour saisir le nom et l'âge de 5 personnes différentes et effectuer un tri de sélection (en fonction de l'âge). J'ai utilisé une classe qui agit comme une structure (comme le langage de programmation C) et une classe principale pour effectuer l'opération complète. Ci-dessous, je fournis le code ...
Le code ci-dessus est sans erreur et testé ... Il suffit de le copier et de le coller dans votre IDE et ... Vous savez et quoi ??? :)
la source
Vous pouvez créer une classe simple avec des champs publics et aucune méthode en Java, mais c'est toujours une classe et elle est toujours gérée syntaxiquement et en termes d'allocation de mémoire comme une classe. Il n'y a aucun moyen de reproduire véritablement des structures en Java.
la source
Parfois, j'utilise une telle classe, lorsque je dois renvoyer plusieurs valeurs d'une méthode. Bien sûr, un tel objet est de courte durée et avec une visibilité très limitée, il devrait donc être OK.
la source
Comme pour la plupart des choses, il y a la règle générale et puis il y a des circonstances spécifiques. Si vous faites une application fermée et capturée afin de savoir comment un objet donné sera utilisé, vous pouvez exercer plus de liberté pour favoriser la visibilité et / ou l'efficacité. Si vous développez une classe qui sera utilisée publiquement par d'autres personnes hors de votre contrôle, penchez-vous vers le modèle getter / setter. Comme pour toutes choses, utilisez simplement le bon sens. Il est souvent correct de faire un premier tour avec des publics, puis de les changer en getter / setters plus tard.
la source
La programmation orientée aspect vous permet d'intercepter des affectations ou des récupérations et d'y attacher une logique d'interception, ce que je propose est la bonne façon de résoudre le problème. (La question de savoir s'ils doivent être publics ou protégés ou protégés par des emballages est orthogonale.)
Ainsi, vous commencez avec des champs non interceptés avec le bon qualificatif d'accès. Au fur et à mesure que les exigences de votre programme augmentent, vous attachez une logique à peut-être valider, faire une copie de l'objet retourné, etc.
La philosophie getter / setter impose des coûts sur un grand nombre de cas simples où ils ne sont pas nécessaires.
Que le style soit plus propre ou non est quelque peu qualitatif. Je trouverais facile de ne voir que les variables d'une classe et de voir la logique séparément. En fait, la raison d'être de la programmation orientée Apect est que de nombreuses préoccupations sont transversales et les compartimenter dans le corps de classe lui-même n'est pas idéal (la journalisation étant un exemple - si vous voulez vous connecter tout obtient Java veut que vous le fassiez) écrire un tas de getters et les garder synchronisés, mais AspectJ vous permet un one-liner).
La question de l'IDE est un sujet redoutable. Ce n'est pas tant la dactylographie que la lecture et la pollution visuelle qui résultent des get / sets.
Les annotations semblent similaires à la programmation orientée aspect à première vue, mais elles vous obligent à énumérer de manière exhaustive les pointcuts en attachant des annotations, par opposition à une spécification concise de caractère générique dans AspectJ.
J'espère que la connaissance d'AspectJ empêche les gens de s'installer prématurément sur des langages dynamiques.
la source