80 votes

Pourquoi ne devrais-je pas utiliser des POJO immuables au lieu de JavaBeans ?

J'ai mis en œuvre quelques applications Java, mais seulement des applications de bureau jusqu'à présent. Je préfère utiliser des objets immuables pour faire circuler les données dans l'application plutôt que d'utiliser des objets avec des mutateurs (setters). et getters ), également appelés JavaBeans.

Mais dans le monde Java, il semble être beaucoup plus courant d'utiliser des JavaBeans, et je ne comprends pas pourquoi je devrais les utiliser à la place. Personnellement, le code semble meilleur s'il ne traite que des objets immuables au lieu de muter l'état tout le temps.

Les objets immuables sont également recommandés dans Point 15 : minimiser la mutabilité , Java efficace 2ed .

Si j'ai un objet Person mis en œuvre en tant que JavaBean ça ressemblerait à ça :

public class Person {
    private String name;
    private Place birthPlace;

    public Person() {}

    public setName(String name) {
        this.name = name;
    }

    public setBirthPlace(Place birthPlace) {
        this.birthPlace = birthPlace;
    }

    public String getName() {
        return name;
    }

    public Place getBirthPlace() {
        return birthPlace;
    }
}

Et la même Person mis en œuvre en tant que immuable objet :

public class Person {
    private final String name;
    private final Place birthPlace;

    public Person(String name, Place birthPlace) {
        this.name = name;
        this.birthPlace = birthPlace;
    }

    public String getName() {
        return name;
    }

    public Place getBirthPlace() {
        return birthPlace;
    }
}

Ou plus proche d'un struct en C :

public class Person {
    public final String name;
    public final Place birthPlace;

    public Person(String name, Place birthPlace) {
        this.name = name;
        this.birthPlace = birthPlace;
    }
}

Je pourrais aussi avoir des getters dans l'objet immuable pour cacher les détails de l'implémentation. Mais comme je ne l'utilise que comme un struct Je préfère éviter les "getters" et rester simple.

Simplement, je ne comprends pas pourquoi il est préférable d'utiliser les JavaBeans, ou si je peux et dois continuer avec mes POJO immuables ?

De nombreuses bibliothèques Java semblent avoir un meilleur support pour les JavaBeans, mais peut-être qu'un meilleur support pour les POJO immuables devient plus populaire avec le temps ?

1 votes

Je pense que vous voulez dire Point 15 : minimiser la mutabilité et non *Minimiser l'immutabilité".

0 votes

@matt : Merci =) Je l'ai mis à jour maintenant.

7 votes

Votre approche de l'immuabilité est excellente, elle vous évite de nombreux problèmes de threads. +1

79voto

Préférer les JavaBeans lorsque

  • vous devez interagir avec des environnements qui les attendent
  • vous avez beaucoup de propriétés pour lesquelles il serait peu commode de faire toute l'initialisation à l'instanciation
  • vous avez un état qui est coûteux ou impossible à copier pour une raison quelconque mais qui nécessite une mutation
  • vous pensez qu'à un moment donné, vous devrez peut-être modifier le mode d'accès aux propriétés (par exemple, passer de valeurs stockées à des valeurs calculées, autorisation d'accès, etc.)
  • vous voulez vous conformer aux normes de codage qui insistent de manière insensée sur le fait que l'utilisation de JavaBeans est en quelque sorte plus "orientée objet".

Préférer les POJO immuables lorsque

  • vous avez un petit nombre de propriétés simples
  • vous ne devez pas interagir avec des environnements supposant des conventions JavaBean
  • il est facile (ou au moins possible) de copier l'état lors du clonage de votre objet.
  • vous ne prévoyez pas de cloner l'objet du tout.
  • vous êtes pratiquement sûr de ne jamais avoir à modifier la façon dont les propriétés sont accédées comme ci-dessus
  • cela ne vous dérange pas d'écouter les pleurnicheries (ou les ricanements) sur le fait que votre code n'est pas suffisamment "orienté objet".

0 votes

+1 pour la liste, et presque -1 pour votre nom :) Après tout, tout le monde sait que c'est mon opinion qui est correcte. Tout le monde étant défini dans le sens de Discworld, bien sûr.

12 votes

La vérification des limites et la validation des entrées peuvent être effectuées dans le constructeur. Si l'entrée est invalide ou hors limites, je ne veux pas créer d'objet.

25 votes

Votre deuxième point n'est pas en faveur des beans, mais en faveur du pattern Builder. Vous pouvez toujours construire un objet immuable.

40voto

Benjamin Wootton Points 1210

J'ai été surpris que le mot Fil conducteur n'apparaît nulle part dans cette discussion.

L'un des principaux avantages des classes immuables est qu'elles sont intrinsèquement plus sûres du fait de l'absence d'état mutable et partagé.

Non seulement cela facilite le codage, mais cela a aussi deux effets secondaires sur les performances :

  • Moins de besoin de synchronisation.

  • Plus de possibilités d'utiliser des variables finales, ce qui peut faciliter les optimisations ultérieures du compilateur.

J'essaie vraiment de me diriger vers des objets immuables plutôt que vers des classes de type JavaBean. Exposer les entrailles des objets via des getters et setters ne devrait probablement pas être le choix par défaut.

19voto

Eh bien, cela dépend de ce que vous essayez de faire. Si vous travaillez avec une couche persistante, et que vous récupérez une ligne de la base de données dans un POJO, et que vous voulez changer une propriété et la sauvegarder, utiliser le style JavaBean serait mieux, surtout si vous avez beaucoup de propriétés.

Considérez que votre personne possède de nombreux champs tels que le prénom, le second prénom, le nom de famille, la date de naissance, les membres de la famille, la formation, l'emploi, le salaire, etc.

Et il se trouve que cette personne est une femme qui vient de se marier et qui a accepté de changer son nom de famille, et vous devez mettre à jour la base de données.

Si vous utilisez un POJO immuable, vous récupérez un objet Personne qui la représente, puis vous créez un nouvel objet Personne auquel vous passez toutes les propriétés que vous n'avez pas modifiées telles quelles, ainsi que le nouveau nom de famille, et vous le sauvegardez.

S'il s'agissait d'un haricot Java, vous pouvez simplement faire setLastName() et l'enregistrer.

C'est "Minimiser la mutabilité" et non "Ne jamais utiliser d'objets mutables". Certaines situations fonctionnent mieux avec des objets mutables, c'est vraiment à vous de décider si rendre un objet mutable convient mieux à votre programme ou non. Vous ne devriez pas toujours dire "doit utiliser des objets immuables", mais plutôt voir combien de classes vous pouvez rendre immuables avant de commencer à vous faire du mal.

2 votes

Mais votre exemple ne correspond presque jamais à ce qui doit être fait dans les applications "réelles". Habituellement, votre objet de données mis à jour doit être transmis à un cadre de validation (Hibernate Validator, Spring Validator, etc.) où l'objet est soumis à diverses opérations, éventuellement écrites par différents développeurs. Si l'objet est mutable, vous ne savez pas si vous travaillez avec les mêmes données qui ont été transmises (si une validation exécutée avant la vôtre a muté l'objet en place). Cela rend le processus de validation moins déterminant, plus dépendant d'un ordre strict, et non parallélisable.

1 votes

En outre, une "vraie" application aura probablement une sorte de cache en mémoire ou distribué (EHCache, etc.) qui contiendra les objets de votre domaine. Si vous savez que vos objets sont immuables, vous n'avez pas besoin d'encourir les frais de copie en lecture. Vous pouvez récupérer et utiliser en toute sécurité l'objet en mémoire sans vous soucier de l'intégrité du cache. À mon avis, pour les objets de ce type dans le domaine de l'entreprise, il faut toujours choisir des objets immuables. Les objets mutables sont OK pour la portée locale et quelques autres cas spécialisés que je n'ai pas les caractères pour entrer ici.

8voto

helios Points 8379

En résumant les autres réponses, je pense que :

  • L'immuabilité facilite la correction (les structures peuvent être transmises par référence et vous savez que rien ne sera détruit par un client défectueux/malicieux) et la simplicité du code.
  • La mutabilité facilite l'homogénéité : Spring et d'autres frameworks créent un objet sans arguments, définissent les propriétés de l'objet, et voi là . Facilitez aussi les interfaces en utilisant la même classe pour donner des données et sauvegarder les modifications (vous n'avez pas besoin de get(id): Client et save(MutableClient) étant MutableClient, un descendant de Client.

S'il y avait un point intermédiaire (créer, définir des propriétés, rendre inmutable), peut-être que les cadres encourageraient davantage une approche inmutable.

Quoi qu'il en soit, je suggère de considérer les objets inamutables comme des "haricots Java en lecture seule", en insistant sur le fait que si vous êtes un bon garçon et que vous ne touchez pas à la dangereuse méthode setProperty, tout ira bien.

0 votes

Je suis d'accord pour dire que le meilleur des deux mondes serait que les bibliothèques et les frameworks adoptent une approche immuable. Les avantages de l'immuable sont intrinsèques, alors que les avantages du mutable sont accessoires.

1voto

extraneon Points 13362

Je ne pense pas que les objets immuables deviendront si populaires, pour être honnête.

J'en vois les avantages, mais les frameworks comme Hibernate et Spring sont actuellement très en vogue (et pour une bonne raison aussi), et ils fonctionnent vraiment mieux avec les beans.

Je ne pense donc pas que l'immuabilité soit mauvaise, mais elle limiterait certainement vos options d'intégration avec les cadres actuels.

EDIT Les commentaires m'incitent à clarifier un peu ma réponse.

Il existe très certainement des domaines problématiques où l'immuabilité est très utile, et est effectivement utilisée. Mais je pense que le défaut actuel semble être d'être mutable car c'est ce que l'on attend le plus, et immuable seulement si cela présente un avantage clair.

Et bien qu'il soit effectivement possible d'utiliser des constructeurs avec des arguments dans Spring, il semble qu'il s'agisse d'un moyen d'utiliser du code hérité et/ou tiers avec votre beau code Spring tout neuf. Du moins, c'est ce que j'ai compris de la documentation.

2 votes

L'idée d'IoC/DI est basée sur l'établissement/injection d'état, c'est pourquoi l'immuabilité n'est pas si populaire dans Spring. Cependant, Joda-Time est un bon exemple d'immutabilité bien faite.

0 votes

Vous pouvez également utiliser les arcs des constructeurs pour injecter des dépendances avec Spring, mais il semble que peu de gens le fassent (peut-être parce que lorsque vous avez beaucoup de dépendances, avoir un constructeur de plus de 10 paramètres est effrayant).

6 votes

@lunohodov : J'ai utilisé Google Guice pour DI/IoC et il n'y a aucun problème pour faire l'injection de dépendance au constructeur.

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