Structurer comme des objets en Java

195

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();
}
Chris de Vries
la source
9
Au lieu de champs publics mutables, considérez les champs publics immuables ou les champs mutables locaux du package. Soit serait mieux à mon humble avis.
Peter Lawrey
N'oubliez pas que, bien que les getters et setters soient moches / verbeux, c'est un peu le cœur de Java. C'est un langage non concis. D'un autre côté, cependant, vous ne devez JAMAIS taper quoi que ce soit, car c'est ce que votre IDE fait pour vous. Dans un langage dynamique, vous devez taper moins, mais vous devez taper (généralement, bien que les IDE puissent aider).
Dan Rosenstark
Ironiquement, alors que OO a ses points forts en termes d'encapsulation, il y a un prix à payer en termes de CPU et de stockage. Le Garbage collector (presque complètement) supprime la nécessité de se soucier du moment où les références d'objet doivent être effacées. La tendance actuelle tourne en boucle en utilisant des structures de type C hors tas. C'est parfait pour les solutions de type mise en cache, les communications inter-processus, les opérations gourmandes en mémoire plus rapides, le GC / h inférieur et peut même bénéficier d'un stockage / h plus faible pour vos ensembles de données. Si vous savez ce que vous faites, vous ne poseriez pas cette question ... alors détrompez-vous!
user924272
@ user924272: Re "La tendance actuelle tourne en boucle en utilisant des structures de type C hors tas". Que feriez-vous en Java comment ??? À mon humble avis, c'est un domaine où Java montre son âge ...
ToolmakerSteve
@ToolmakerSteve -Je vois un cercle. Je ne suis pas le seul. Des entreprises comme Azul sont passionnées par la collecte des ordures sans pause. Java est vieux. Vrai. Des ingénieurs qui repèrent une faiblesse et y font quelque chose, plutôt que de gémir? Ils méritent le respect! +10 à Azul de ma part :-)
user924272

Réponses:

62

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:

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

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

Bartosz Bierkowski
la source
28
C'est dommage, j'aime les propriétés de style C # (ce qui ressemble à ce dont vous parlez)
Jon Onstott
2
Utilisez donc la surcharge ... private int _x; public void x (int value) {_x = value; } public int x () {return _x; }
Gordon
12
Je préfère pouvoir l'utiliser =, ce qui à mon avis rend le code plus propre.
Svish
6
@ T-Bull: Ce xn'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.
ToolmakerSteve
2
@ToolmakerSteve: Cela "pourrait conduire à la confusion" est l'argument le plus courant et toujours le plus faible lorsqu'il s'agit de défendre le dogme du codage (par opposition au style de codage). Il y a toujours quelqu'un qui POURRAIT être dérouté par les choses les plus simples. Vous trouverez toujours quelqu'un se plaindre d'avoir fait une erreur après être resté éveillé et avoir codé pendant une demi-semaine ou quelque chose comme ça, puis blâmer le style de codage trompeur. Je ne laisse pas cela compter. Ce style est valide, évident et maintient l'espace de noms propre. De plus, il n'y a pas d'entités différentes ici, il y a / one / entity et du code passe-partout autour.
T-Bull
290

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

developer.g
la source
88
+1 Pour avoir réellement une source faisant autorité. Toutes les autres réponses sont que les gens tournent leurs opinions comme s'ils étaient des faits.
ArtOfWarfare
1
Il existe une spécification Java Beans qui est un moyen standard d'accéder aux propriétés à l'aide des méthodes get et set ... voir en.wikipedia.org/wiki/JavaBeans pour un aperçu.
user924272
4
@ user924272: En quoi cette spécification Java Beans est-elle pertinente pour cette réponse, qui explique quand il convient d'utiliser des "variables d'instance publique"? Si la spécification était un moyen standard de transformer automatiquement des variables d'instance en propriétés, ala C #, cela pourrait être pertinent. Mais ce n'est pas le cas, non? Il spécifie simplement la dénomination des getters et setters passe-partout qui devraient être créés pour effectuer une telle cartographie.
ToolmakerSteve
@ToolmakerSteve. Ceci est une question java. De plus, la question échappe à un problème courant lorsqu'une spécification existe. Du point de vue de la vieille école, il est beaucoup plus facile de déboguer les mutations de champ quand il existe une façon standard de le faire - définir un point d'arrêt sur un setter. Cela a probablement été rendu obsolète avec les débogueurs modernes, mais je suis obligé de froncer les sourcils sur les classes qui "perforent" directement les objets ... bien que cela soit acceptable pour les petites applications, c'est un vrai casse-tête pour les grandes applications et les grandes organisations
user924272
223

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

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

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:

public class BankAccount{
    public int balance;
}

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.

izb
la source
3
Je suis d'accord avec cette réponse et je dis plus loin que vous pouvez créer une classe avec des champs publics tant que les champs sont en gras indépendamment les uns des autres. c'est-à-dire qu'un champ ne dépend pas d'un autre. Cela peut être très utile dans de nombreux cas, pour plusieurs valeurs de retour d'une fonction, ou pour des co-odinates polaires. {angle, longueur} qui vont de pair mais ne dépendent pas les uns des autres de façon intrinsèque.
Spacen Jasset
@SpacenJasset: Pour info, je ne vois pas comment vos exemples (plusieurs valeurs de retour; coordonnées polaires) ont une incidence sur l'utilisation des champs publics vs getter / setters. Dans le cas de plusieurs valeurs de retour, cela pourrait même être contre-productif, car sans doute l'appelant ne devrait OBTENIR que les valeurs renvoyées, ce qui plaide en faveur des getters publics et des setters privés (immuables). Cela peut également être vrai pour le retour de coordonnées polaires à partir d'un objet (x, y) - tenez compte des erreurs mathématiques ACCUMULATIVES, car les modifications apportées aux composants individuels des coordonnées polaires sont reconverties en (x, y).
ToolmakerSteve
@SpacenJasset: Mais je suis d'accord avec votre principe.
ToolmakerSteve
1
Vous avez un point valide, mais j'ai l'impression que la chose pixels est un mauvais exemple car s'assurer que le pixel est dans la fenêtre (juste un exemple) est quelque chose que quelqu'un pourrait faire, et en plus, laisser quelqu'un régler le pixel (-5, -5)pourrait ne pas être une bonne idée. :-)
Horsey
50

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

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

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

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 * d.x) / d.y;
    }

    public static void main(String[] args) {
        DataTest dataTest = new DataTest();
    }
}
Brian
la source
3
Merci - une réponse utile et concise. Montre comment tirer parti de la syntaxe des champs, lorsque vous ne voulez pas de mutabilité.
ToolmakerSteve
@ToolmakerSteve - merci pour les commentaires - très apprécié.
Brian
J'ai essayé d'utiliser les instances finales d'une classe finale avec des champs finaux comme struct "instances", mais dans une caseexpression faisant référence à un tel champ d'instance, j'ai réussi Case expressions must be constant expressions. quelle est la solution? quel est le concept idiomatique ici?
n611x007
1
les champs finaux sont toujours des références à des objets, qui ne sont pas des constantes, car ils seront initialisés lors de la première utilisation de la classe. Le compilateur ne peut pas connaître la "valeur" des références d'objet. Les constantes doivent être connues lors de la compilation.
Johan Tidén
1
+1 Réponse vraiment importante. L'utilité des classes immuables ne peut pas être sous-estimée à mon avis. Leur sémantique "tirer et oublier" rend le raisonnement sur le code souvent plus simple, en particulier dans les environnements multithread, où ils peuvent être partagés arbitrairement entre les threads, sans synchronisation.
TheOperator
11

N'utilisez pas de publicchamps

N'utilisez pas de publicchamps lorsque vous voulez vraiment envelopper le comportement interne d'une classe. Prenez java.io.BufferedReaderpar exemple. Il a le champ suivant:

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

skipLFest 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 de skipLFau milieu d'une lecture? BufferedReaderira certainement détraqué.

Utilisez des publicchamps

Prenez ce Pointcours 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 le calcul de la distance entre deux points très pénible à écrire.

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 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:

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(b.x - a.x, 2) + Math.pow(b.y - a.y, 2));

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" :

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 structau lieu d'une classe (si Java était pris en charge struct), il est approprié de rendre publiques les variables d'instance de la classe.

La documentation officielle accepte donc également cette pratique.)


De plus, si vous êtes très sûr que les membres de la Pointclasse ci - dessus doivent être immuables, vous pouvez ajouter un finalmot clé pour l'appliquer:

public final double x;
public final double y;
sampathsris
la source
8

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).

Spoike
la source
+1 Bonne mention d'un problème - une manière dont le résultat n'est toujours PAS comme une structure C. Cependant, le problème que vous soulevez à propos des objets java toujours par référence n'est pas amélioré en créant un setter au lieu d'avoir un champ accessible en écriture (ce qui est l'essence de la question d'OP - quelle représentation utiliser). C'est plutôt un argument en faveur de ne faire rien. C'est un argument pour l'IMMUTABILITÉ. Ce qui peut être fait en tant que public finalchamp, 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.
ToolmakerSteve
8

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.

Mark Renouf
la source
12
Comment un getter / setter résout ce problème. Vous avez toujours une référence, vous n'avez aucune synchronisation avec les opérations. Les getters / setters ne fournissent pas de protection en soi.
he_the_great
1
Les getters et setters peuvent assurer la synchronisation si nécessaire. Vous vous attendez également à ce que les getters et les setter fassent beaucoup plus que ce qu'ils étaient censés faire. Indépendamment de cela, le problème de synchronisation persiste encore.
user924272
7

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:

  • À peu près n'importe quel outil automatisé dans le monde java repose sur la convention getter / setter. Idem pour, comme indiqué par d'autres, les balises jsp, la configuration du ressort, les outils d'éclipse, etc. etc ... Lutter contre ce que vos outils s'attendent à voir est une recette pour de longues sessions parcourant google en essayant de trouver cette façon non standard d'initier haricots de printemps. Vraiment pas la peine.
  • Une fois que vous avez votre application élégamment codée 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, ou vous voulez lancer une exception sur un changement de variable car il définit un état d'objet sur quelque chose de 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, ayant un formulaire d'accès spécial pour 3 des 1000 variables de votre application.

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.

Steve B.
la source
Excellente discussion sur les problèmes de descendre la route des domaines publics. Une lacune certaine de Java, qui m'agace quand je dois revenir à Java à partir de C # (qui a appris des inconvénients de Java ici).
ToolmakerSteve
4

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.

brabster
la source
1
+1 pour le lien vers l'article "Pourquoi les méthodes Getter et Setter sont mauvaises". Cependant, votre réponse aurait été plus claire si vous aviez souligné que LES DEUX champs publics ET les getter / setters publics ne sont ÉGALEMENT PAS la manière Java: Comme expliqué dans cet article - lorsque cela est possible, ne faites pas non plus. Au lieu de cela, fournissez aux clients des méthodes spécifiques à ce qu'ils doivent faire, plutôt que de refléter la représentation interne de l'instance. CEPENDANT, cela ne répond pas vraiment à la question posée (laquelle utiliser, pour un cas simple "struct"), qui est mieux répondue par developer.g, izb et Brian.
ToolmakerSteve
3

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.

luis.espinal
la source
l'ananas me fait rire :)
Guillaume
Cependant, cette réponse ne dit rien sur cette différence. Ragging sur des développeurs non qualifiés n'aide pas ces développeurs à savoir quand créer une structure et quand créer une classe.
ToolmakerSteve
Il ne dit rien sur la différence car l'auteur est conscient de la différence (il sait ce qu'est une entité de type struct). L'auteur demande si l'utilisation de structures est appropriée dans un langage OO, et je dis oui (en fonction du domaine problématique.) Si la question était de savoir ce qui fait d'un objet un véritable objet de domaine, alors vous auriez une jambe pour vous argument.
luis.espinal
De plus, le seul type de développeur non qualifié qui ne devrait pas faire la différence serait celui qui est encore à l'école. Ceci est extrêmement fondamental, comme connaître la différence entre une liste chaînée et une table de hachage. Si une personne obtient un diplôme en logiciel de 4 ans sans savoir ce qu'est un véritable objet, alors cette personne n'est pas coupée pour cette carrière, ou elle devrait retourner à l'école et demander un remboursement. Je suis serieux.
luis.espinal
Mais pour satisfaire votre plainte, je vous fournirai une réponse (qui n'a rien à voir avec la question initiale et qui mérite son propre fil). Les objets ont un comportement et encapsulent l'état. Les structures ne le font pas. Les objets sont des machines à états. Les structures sont juste pour agréger des données. Si les gens veulent une réponse plus élaborée, ils sont libres de créer une nouvelle question où nous pouvons la développer à notre guise.
luis.espinal
2

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.

Alex Miller
la source
1
C'est vrai, mais si vous utilisez Java, ce n'est pas un problème, car vous pouvez refactoriser une base de code entière en un seul clic (Eclipse, Netbeans, probablement VIM et Emacs aussi). Si vous avez opté pour l'un de ses amis dynamiques, comme Groovy, même une simple encapsulation pourrait vous faire réparer pendant des heures ou des jours. Heureusement, vous auriez vos cas de test qui vous informeraient ... combien de code supplémentaire vous devez corriger.
Dan Rosenstark
2
Vous supposez bien sûr que tous les utilisateurs sont dans votre base de code, mais bien sûr, ce n'est souvent pas vrai. Souvent, il n'est même pas possible pour diverses raisons non techniques de modifier le code qui pourrait se trouver dans votre propre base de code.
Alex Miller
2

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é.

Kris Nuttycombe
la source
2

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

stream.mapToInt(SomeData1::x)

n'est pas légal, mais

stream.mapToInt(SomeData2::getX)

est.

Lyubomyr Shaydariv
la source
Dans ce cas, vous pouvez utiliser data -> data.x, ce qui est toujours raisonnable
James Kraus
1

Je 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.

John Topley
la source
1

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.

Jonathan
la source
1

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 ...

import java.io.*;

class NameList {
    String name;
    int age;
}

class StructNameAge {
    public static void main(String [] 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 ??? :)

Avik Kumar Goswami
la source
0

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.

cblades
la source
0

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.

PhiLho
la source
0

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.

Evvo
la source
0

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.

nécromancien
la source