198 votes

Des structures comme des objets en Java

Est-il totalement contraire à la méthode Java de créer des objets de type struct ?

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

Je peux imaginer qu'une classe avec des accesseurs et des mutateurs soit plus proche de 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 notationnellement commode.

// 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();
}

303voto

developer.g Points 1117

Il semble que de nombreux utilisateurs de Java ne connaissent pas les directives de codage de Sun Java qui disent qu'il est tout à fait approprié d'utiliser une variable d'instance publique quand la classe est essentiellement un "Struct", si Java supportait le "struct" (quand il n'y a pas de comportement).

Les gens ont tendance à penser que les getters et setters sont la méthode 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 publiques dans les situations appropriées, vous écrivez en fait un meilleur code qu'en l'encombrant de getters et setters inutiles.

Conventions de code Java de 1999 et toujours inchangé.

10.1 Fournir un accès aux variables d'instance et de classe

Ne rendez pas une 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 récupérées - cela se produit souvent comme un effet secondaire des appels de méthode.

Un exemple de variables d'instance publiques appropriées 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 Java supportait les structures), 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

224voto

izb Points 12736

Faites preuve de bon sens. Si vous avez quelque chose comme

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

Alors il n'y a pas de raison de les emballer dans des getters et setters. Vous n'allez jamais stocker une coordonnée x,y en pixels entiers d'une autre manière. Les getters et setters ne font que vous ralentir.

D'autre part, avec

public class BankAccount
{
    public int balance;
}

vous pourriez vouloir changer la façon dont un solde est calculé à un moment donné dans le futur. Il faudrait vraiment utiliser des getters et des setters.

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

62voto

bibix Points 1915

Ce sujet est souvent repris. L'inconvénient de créer des champs publics dans les objets est que vous n'avez aucun contrôle sur les valeurs qui leur sont attribuées. Et parfois, il est 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 simuler de telles 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 la programmation défensive - un jour, les getters et setters peuvent être utiles et cela ne coûte pas cher de les créer/utiliser. Ils sont donc parfois utiles.

En pratique, la plupart des champs ont des getters et setters simples. C'est pourquoi, dans Java 7, des propriétés seront probablement ajoutées, qui se comporteront comme des champs normaux, à moins que vous n'ayez besoin de plus de contrôle sur l'obtention/le réglage d'une valeur. La question fait toujours l'objet de discussions. L'une des solutions possibles serait la suivante :

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

Vous pouvez en savoir plus à ce sujet sur Java 7 d'Alex Miller page.

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. supportent cette fonctionnalité maintenant. - Alex Miller

54voto

Brian Points 7072

Pour résoudre les problèmes de mutabilité, vous pouvez déclarer x et y comme finaux. 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 appelant qui tente d'écrire dans ces champs obtiendra une erreur de compilation du type "le champ x est déclaré final ; il ne peut pas être attribué".

Le code client peut alors bénéficier de la commodité du "raccourci" que vous avez décrit 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();
    }
}

8voto

Mark Renouf Points 13128

Re : aku, izb, John Topley...

Attention aux problèmes de mutabilité...

Il peut sembler judicieux d'omettre les getters/setters. Cela peut même être acceptable dans certains cas. Le vrai problème avec le modèle proposé ici est la mutabilité.

Le problème est qu'une fois que vous passez une référence d'objet contenant des champs non finaux et publics. 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 objet. (Pensez à ce qui se passerait si les chaînes de caractères étaient mutables).

Les choses se gâtent lorsque cet objet est une partie importante de l'état interne d'un autre, dont vous venez d'exposer l'implémentation interne. Pour éviter cela, une copie de l'objet doit être retournée à la place. Cela fonctionne, mais peut causer une pression GC massive à cause des 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 paramètres au constructeur, et marquez les champs comme finaux. Sinon, assurez-vous de ne pas exposer 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.

Voyez : " Java efficace "par Joshua Bloch -- Point n° 13 : Favoriser l'immuabilité.

PS : N'oubliez pas non plus que toutes les JVM actuelles optimisent la méthode getMethod si possible, ce qui se traduit par une seule instruction de lecture de champ.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X