Struct comme des objects en Java

Est-ce complètement opposé à la manière Java de créer des objects structurés?

class SomeData1 { public int x; public int y; } 

Je peux voir une classe avec des accesseurs et des mutateurs plus comme 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 commode sur le plan de la notation.

 // a function in a class public int f(SomeData1 d) { return (3 * dx) / dy; } 

Ce n’est pas aussi pratique.

 // a function in a class public int f(SomeData2 d) { return (3 * d.getX()) / d.getY(); } 

C’est un sujet couramment discuté. L’inconvénient de la création de champs publics dans les objects est que vous n’avez aucun contrôle sur les valeurs qui y 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 retourner une copie de l’object du champ ou de le transformer en quelque sorte, etc. Vous pouvez simuler ces méthodes dans vos tests. Si vous créez une nouvelle classe, vous risquez de ne pas voir toutes les actions possibles. C’est comme une programmation défensive. Un jour, les formateurs peuvent être utiles et leur création / utilisation ne coûte pas cher. Ils sont donc parfois utiles.

En pratique, la plupart des champs ont des getters et des setters simples. Une solution possible ressemblerait à ceci:

 public property Ssortingng foo; a->Foo = b->Foo; 

Mise à jour: Il est hautement improbable que le support des propriétés soit ajouté à Java 7 ou peut-être jamais. D’autres langages JVM tels que Groovy, Scala, etc. supportent cette fonctionnalité maintenant. – Alex Miller

Il semble que de nombreuses personnes Java ne sont pas familiarisées avec les directives Sun Java Coding, qui indiquent qu’il est tout à fait approprié d’utiliser une variable d’instance publique lorsque la classe est essentiellement une “Struct”, si Java supporte “struct”.

Les gens ont tendance à penser que les getters et les installateurs sont la voie Java, comme s’ils étaient au cœur de Java. Ce n’est pas le cas. Si vous suivez les Sun Java Coding Guidelines, en utilisant des variables d’instance publique dans des situations appropriées, vous écrivez en fait un code plus efficace que de l’encombrer avec des getters et des setters inutiles.

Conventions du code Java de 1999 et toujours inchangées.

10.1 Fourniture d’access aux variables d’instance et de classe

Ne rendez aucune variable de classe ou d’instance publique sans raison valable. Souvent, les variables d’instance n’ont pas besoin d’être explicitement définies ou obtenues, ce qui se produit souvent comme un effet secondaire des appels de méthode.

Un exemple de variable d’instance publique appropriée est le cas où la classe est essentiellement une structure de données, sans comportement. En d’autres termes, si vous aviez utilisé une structure au lieu d’une classe (si struct pris en charge par Java), il convient 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

Utilisez le bon sens vraiment. Si vous avez quelque chose comme:

 public class ScreenCoord2D{ public int x; public int y; } 

Ensuite, il ne sert à rien de les envelopper dans les getters et les setters. Vous n’allez jamais stocker une coordonnée x, y en pixels entiers d’une autre manière. Les getters et les setters ne feront que vous ralentir.

D’autre part, avec:

 public class BankAccount{ public int balance; } 

Vous voudrez peut-être changer la façon dont un solde est calculé à un moment donné dans le futur. Cela devrait vraiment utiliser les getters et les setters.

Il est toujours préférable de savoir pourquoi vous appliquez les bonnes pratiques, de sorte que vous sachiez quand il est permis de contourner les règles.

Pour résoudre les problèmes de mutabilité, vous pouvez déclarer x et y comme final. Par exemple:

 class Data { public final int x; public final int y; public Data( int x, int y){ this.x = x; this.y = y; } } 

Le code d’appel qui tente d’écrire dans ces champs recevra une erreur de compilation du “champ x est déclaré final; ne peut pas être atsortingbué”.

Le code client peut alors avoir la commodité «raccourcie» que vous avez décrite dans votre message.

 public class DataTest { public DataTest() { Data data1 = new Data(1, 5); Data data2 = new Data(2, 4); System.out.println(f(data1)); System.out.println(f(data2)); } public int f(Data d) { return (3 * dx) / dy; } public static void main(Ssortingng[] args) { DataTest dataTest = new DataTest(); } } 

Re: aku, izb, John Topley …

Attention aux problèmes de mutabilité …

Il peut sembler judicieux d’omettre les getters / setters. En fait, cela peut aller dans certains cas. Le vrai problème avec le modèle proposé montré ici est la mutabilité.

Le problème est une fois que vous passez une référence d’object contenant des champs publics non finaux. Toute autre chose avec cette référence est libre de modifier ces champs. Vous n’avez plus aucun contrôle sur l’état de cet object. (Pensez à ce qui arriverait si les cordes étaient mutables.)

Cela devient mauvais quand cet object est une partie importante de l’état interne d’un autre, vous venez juste d’exposer une implémentation interne. Pour éviter cela, une copie de l’object doit être renvoyée à la place. Cela fonctionne, mais peut provoquer une pression GC massive à partir de tonnes de copies à usage unique créées.

Si vous avez des champs publics, envisagez de rendre la classe en lecture seule. Ajoutez les champs en tant que parameters au constructeur et marquez les champs finaux. Sinon, assurez-vous de ne pas exposer l’état interne et, si vous avez besoin de construire de nouvelles instances pour une valeur de retour, assurez-vous qu’il ne sera pas appelé de manière excessive.

Voir: ” Effective Java ” de Joshua Bloch – Article n ° 13: Favoriser l’immuabilité.

PS: gardez également à l’esprit que tous les JVMs vont optimiser la méthode getMethod si possible, ne produisant qu’une seule instruction de lecture de champ.

Ne pas utiliser public champs public

N’utilisez pas de champs public lorsque vous voulez vraiment envelopper le comportement interne d’une classe. Prenez java.io.BufferedReader par exemple. Il a le champ suivant:

 private boolean skipLF = false; // If the next character is a line feed, skip it 

skipLF est lu et écrit dans toutes les méthodes de lecture. Que se passe-t-il si une classe externe s’exécutant dans un thread séparé a modifié de manière malveillante l’état de skipLF au milieu d’une lecture? BufferedReader va certainement tourner en rond.

Utilisez public champs public

Prenez cette classe de Point par exemple:

 class Point { private double x; private double y; public Point(double x, double y) { this.x = x; this.y = y; } public double getX() { return this.x; } public double getY() { return this.y; } public void setX(double x) { this.x = x; } public void setY(double y) { this.y = y; } } 

Cela rendrait difficile le calcul de la distance entre deux points.

 Point a = new Point(5.0, 4.0); Point b = new Point(4.0, 9.0); double distance = Math.sqrt(Math.pow(b.getX() - a.getX(), 2) + Math.pow(b.getY() - a.getY(), 2)); 

La classe n’a pas d’autre comportement que les manifestants et les poseurs. Il est acceptable d’utiliser des champs publics lorsque la classe ne représente qu’une structure de données, et qu’elle n’a pas et n’aura jamais de comportement (les règles et méthodes de réglage fines ne sont pas considérées comme un comportement ici). Cela peut être mieux écrit de cette façon:

 class Point { public double x; public double y; public Point(double x, double y) { this.x = x; this.y = y; } } Point a = new Point(5.0, 4.0); Point b = new Point(4.0, 9.0); double distance = Math.sqrt(Math.pow(bx - ax, 2) + Math.pow(by - ay, 2)); 

Nettoyer!

Mais souvenez-vous que non seulement votre classe doit être absente du comportement, mais qu’elle ne devrait pas non plus avoir de comportement à l’avenir.

Au fait, 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-le vous-même .

Si vous savez ce que vous faites et que d’autres membres de votre équipe le savent, alors il est possible d’avoir des champs publics. Mais vous ne devriez pas vous y fier car ils peuvent causer des maux de tête comme dans les bogues liés aux développeurs utilisant des objects comme s’ils étaient des structures allouées par stack (les objects Java sont toujours envoyés aux méthodes en tant que références et non en tant que copies).

J’ai essayé ceci dans quelques projets, sur la théorie que les getters et les setters encombrent le code avec une impossibilité sémantique, et que d’autres langages semblent bien fonctionner avec le masquage des données ou le partitionnement des responsabilités (python par exemple).

Comme d’autres l’ont noté ci-dessus, il y a 2 problèmes que vous rencontrez, et ils ne sont pas vraiment réparables:

  • À peu près tous les outils automatisés du monde Java reposent sur la convention getter / setter. Idem pour, comme noté par d’autres, les balises jsp, la configuration du spring, les outils d’éclipse, etc. La lutte contre ce que vos outils attendent de voir est une recette pour de longues sessions à la recherche de cette méthode non standardisée. haricots de spring. Vraiment pas la peine.
  • Une fois que vous avez votre application codée de manière élégante avec des centaines de variables publiques, vous trouverez probablement au moins une situation où elles sont insuffisantes – où vous avez absolument besoin d’immuabilité, ou vous devez déclencher un événement lorsque la variable est définie. une exception sur une variable change car elle définit un état d’object désagréable. Vous êtes alors coincé avec les choix peu enviables entre encombrer votre code avec une méthode spéciale partout où la variable est directement référencée, avec un formulaire d’access spécial pour 3 des 1000 variables de votre application.

Et dans le meilleur des cas, travailler entièrement dans un projet privé autonome. Une fois que vous exportez le tout dans une bibliothèque accessible au public, ces problèmes deviendront encore plus importants.

Java est très verbeux, et c’est tentant à faire. Ne le fais pas

Si la méthode Java est la méthode OO, alors oui, la création d’une classe avec des champs publics rompt les principes autour du masquage des informations, indiquant qu’un object doit gérer son propre état interne. (Donc, comme je ne vous lance pas seulement le jargon, un avantage de la dissimulation d’informations est que le fonctionnement interne d’une classe est caché derrière une interface – par exemple, vous voulez modifier le mécanisme par lequel votre classe vous devrez probablement revenir en arrière et changer les classes qui utilisent la classe …)

Vous ne pouvez pas non plus tirer parti de la prise en charge des classes compatibles avec le nommage JavaBean, ce qui nuira si vous décidez, par exemple, d’utiliser la classe dans une page JavaServer écrite à l’aide d’Expression Language.

L’article de JavaWorld Pourquoi les méthodes de mise en place et de mise en place sont-elles un article qui pourrait également vous intéresser lorsque vous ne devez pas mettre en œuvre les méthodes des accesseurs et des mutateurs.

Si vous écrivez une petite solution et que vous souhaitez minimiser la quantité de code impliquée, 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.

Il n’y a rien de mal avec ce type de code, à condition que l’auteur sache qu’il s’agit de structures (ou de navettes de données) au lieu d’objects. Beaucoup de développeurs Java ne peuvent pas faire la différence entre un object bien formé (pas seulement une sous-classe de java.lang.Object, mais un véritable object dans un domaine spécifique) et un ananas. Ergo, ils finissent par écrire des structures quand ils ont besoin d’objects et vice versa.

Le problème avec l’utilisation de l’access aux champs publics est le même que celui de l’utilisation d’une nouvelle méthode plutôt que d’une méthode par défaut: si vous changez d’avis plus tard, tous les appelants existants sont brisés. Donc, du sharepoint 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’access à la classe, par exemple dans une classe statique interne utilisée comme structure de données interne. Dans ce cas, il peut être beaucoup plus clair d’utiliser l’access aux champs.

En passant, sur l’affirmation d’e-bartek, il est hautement improbable que l’OMI ajoute un support de propriété dans Java 7.

J’utilise fréquemment ce modèle lors de la création de classes internes privées pour simplifier mon code, mais je ne recommande pas d’exposer de tels objects dans une API publique. En général, plus vous pouvez rendre les objects de votre API publique immuables, mieux c’est, et il n’est pas possible de construire votre object struct-like de manière immuable.

En passant, même si j’écrivais cet object en tant que classe interne privée, je fournirais tout de même un constructeur pour simplifier le code afin d’initialiser l’object. Avoir besoin de 3 lignes de code pour obtenir un object utilisable quand on le fait est tout simplement compliqué.

Une très vieille question, mais permettez-moi de faire une autre petite consortingbution. Java 8 a introduit les expressions lambda et les 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. Ainsi

 stream.mapToInt(SomeData1::x) 

n’est pas légal, mais

 stream.mapToInt(SomeData2::getX) 

est.

Je ne vois pas le mal si vous savez que ça va toujours être une structure simple et que vous ne voudrez jamais y attacher un comportement.

Ceci est une question sur la conception orientée object, 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 faisant partie de l’API de classe. Si vous exposez des types de données internes, vous ne pourrez jamais les modifier ultérieurement. Si vous les masquez, votre seule obligation envers l’utilisateur est le type de retour et d’argument de la méthode.

Ici, je crée un programme pour saisir le nom et l’âge de 5 personnes différentes et effectuer un sorting 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 …

 import java.io.*; class NameList { Ssortingng name; int age; } class StructNameAge { public static void main(Ssortingng [] args) throws IOException { NameList nl[]=new NameList[5]; // Create new radix of the structure NameList into 'nl' object NameList temp=new NameList(); // Create a temporary object of the structure BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); /* Enter data into each radix of 'nl' object */ for(int i=0; i<5; i++) { nl[i]=new NameList(); // Assign the structure into each radix System.out.print("Name: "); nl[i].name=br.readLine(); System.out.print("Age: "); nl[i].age=Integer.parseInt(br.readLine()); System.out.println(); } /* Perform the sort (Selection Sort Method) */ for(int i=0; i<4; i++) { for(int j=i+1; j<5; j++) { if(nl[i].age>nl[j].age) { temp=nl[i]; nl[i]=nl[j]; nl[j]=temp; } } } /* Print each radix stored in 'nl' object */ for(int i=0; i<5; i++) System.out.println(nl[i].name+" ("+nl[i].age+")"); } } 

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 ??? 🙂

Vous pouvez créer une classe simple avec des champs publics et aucune méthode en Java, mais il s’agit toujours d’une classe et est toujours manipulée syntaxiquement et en termes d’allocation de mémoire, tout comme une classe. Il n’y a aucun moyen de reproduire véritablement les structures en Java.

Parfois, j’utilise une telle classe, lorsque je dois retourner plusieurs valeurs d’une méthode. Bien sûr, un tel object est de courte durée et avec une visibilité très limitée, donc ça devrait aller.

Comme avec la plupart des choses, il y a la règle générale et il y a des circonstances spécifiques. Si vous faites une application capturée fermée afin de savoir comment un object donné va être utilisé, vous pouvez alors exercer plus de liberté pour favoriser la visibilité et / ou l’efficacité. Si vous développez une classe qui sera utilisée publiquement par des personnes indépendantes de votre volonté, penchez-vous vers le modèle getter / setter. Comme avec toutes les choses, utilisez simplement le bon sens. Il est souvent acceptable de faire un premier tour avec les publics, puis de les changer en getter / setters plus tard.

La programmation orientée aspect vous permet de piéger des affectations ou des récupérations et de leur associer une logique d’interception, ce qui est le bon moyen de résoudre le problème. (La question de savoir si elles doivent être publiques ou protégées ou protégées par des packages est orthogonale.)

Ainsi, vous commencez avec des champs non interceptés avec le bon qualificatif d’access. Au fur et à mesure que les exigences de votre programme évoluent, vous devez associer une logique pour peut-être valider, faire une copie de l’object renvoyé, 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 voir uniquement les variables d’une classe et de voir la logique séparément. En fait, la raison d’être de la programmation orientée vers l’Apect est que de nombreuses préoccupations sont transversales et que leur compartimentage dans le corps même de la classe n’est pas idéal (la journalisation étant un exemple – si vous voulez vous connecter, Java vous demande de écrire tout un tas de getters et les garder en phase mais AspectJ vous permet un one-liner).

La question de l’IDE est un problème sérieux. Ce n’est pas tant la dactylographie que la lecture et la pollution visuelle qui découlent de get / sets.

Les annotations semblent similaires à la programmation orientée aspect à première vue, mais elles nécessitent que vous énumériez de manière exhaustive les points de repère en joignant des annotations, par opposition à une spécification concise de type point-wild dans AspectJ.

J’espère que la sensibilisation à AspectJ empêche les gens de s’installer prématurément dans des langues dynamics.