web-dev-qa-db-fra.com

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

J'ai implémenté quelques applications Java maintenant, seules des applications de bureau jusqu'à présent. Je préfère utiliser des objets immuables pour transmettre 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 qu'il soit beaucoup plus courant d'utiliser JavaBeans, et je ne comprends pas pourquoi je devrais les utiliser à la place. Personnellement, le code semble meilleur s'il ne traite que d'immuable objets au lieu de muter l'état tout le temps.

Les objets immuables sont également recommandés dans Item 15: Minimize mutability, Effective Java 2ed .

Si j'ai un objet Person implémenté comme JavaBean il ressemblerait à:

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 le même Person implémenté comme un objet immuable:

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 également avoir des getters dans l'objet immuable pour cacher les détails de l'implémentation. Mais comme je ne l'utilise que comme struct, je préfère ignorer les "getters" et rester simple.

Simplement, je ne comprends pas pourquoi il vaut mieux utiliser JavaBeans, ou si je peux et dois continuer avec mes POJO immuables?

La plupart des bibliothèques Java Java semblent avoir un meilleur support pour JavaBeans, mais peut-être que plus de support pour les POJO immuables devient plus populaire au fil du temps?

79
Jonas

Préférez JavaBeans lorsque

  • vous devez interagir avec les environnements qui les attendent
  • vous avez beaucoup de propriétés pour lesquelles il serait gênant de faire toute l'initialisation lors de 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 des valeurs stockées aux valeurs calculées, autorisation d'accès, etc.)
  • vous voulez vous conformer aux normes de codage qui insistent insensément sur le fait qu'il est en quelque sorte plus "orienté objet" d'utiliser JavaBeans

Préférez les POJO immuables lorsque

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

J'ai été surpris que le mot Thread n'apparaisse nulle part dans cette discussion.

L'un des principaux avantages des classes immuables est qu'elles sont intrinsèquement plus sûres pour les threads en raison de l'absence d'état mutable partagé.

Non seulement cela facilite votre codage, mais cela vous donnera également deux avantages en termes de performances comme effet secondaire:

  • Moins de besoin de synchronisation.

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

J'essaie vraiment d'aller vers des objets immuables plutôt que vers des classes de style JavaBean. L'exposition des entrailles des objets via des getters et setters ne devrait probablement pas être le choix par défaut.

38
Benjamin Wootton

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 souhaitez modifier une propriété et la sauvegarder, l'utilisation du style JavaBean serait préférable, surtout si vous avez beaucoup de propriétés.

Considérez que votre personne a beaucoup de domaines comme le prénom, le deuxième prénom, le nom de famille, la date de naissance, les membres de la famille, l'éducation, l'emploi, le salaire, etc.

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

Si vous utilisez POJO immuable, vous récupérez un objet Person qui la représente, puis vous créez un nouvel objet Person auquel vous transmettez toutes les propriétés que vous n'avez pas modifiées telles qu'elles sont, et le nouveau nom de famille, et enregistrez-le.

S'il s'agissait d'un bean Java bean, 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 conviendra mieux à votre programme ou non. Vous ne devriez pas toujours dire "doit utiliser des objets immuables", voyez plutôt combien de classes vous pouvez rendre immuables avant de commencer à vous faire du mal.

16
Andrei Fierbinteanu

Résumant d'autres réponses, je pense que:

  • l'inutilité facilite l'exactitude (les structures peuvent être transmises par référence et vous savez que rien ne sera détruit par un client défectueux/malveillant) 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 également les interfaces en utilisant la même classe pour fournir des données et enregistrer des modifications (vous n'avez pas besoin de get(id): Client et save(MutableClient), MutableClient étant un descendant de Client.

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

Quoi qu'il en soit, je suggère de penser aux objets immuables comme "lecture seule Java Beans"), soulignant le fait que si vous êtes un bon garçon et ne touchez pas à cette dangereuse méthode setProperty, tout ira bien.

7
helios

Depuis Java 7, vous pouvez avoir des beans immuables, le meilleur des deux mondes. Utilisez l'annotation @ConstructorProperties sur votre constructeur.

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

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

    public String getName() {
        return name;
    }

    public Place getBirthPlace() {
        return birthPlace;
    }
}
3
Larry

Pour être honnête, je ne pense pas que les objets immuables deviennent si populaires.

Je 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 cela limiterait certainement vos options d'intégration avec les frameworks actuels.

MODIFIER Les commentaires m'invitent à clarifier un peu ma réponse.

Il y a très certainement des problèmes où l'immuabilité est très utile, et est en effet utilisée. Mais je pense que la valeur par défaut actuelle semble être modifiable car c'est ce qui est généralement attendu, et immuable uniquement si cela a un avantage clair.

Et bien qu'il soit en effet possible d'utiliser des constructeurs avec des arguments dans Spring, cela semble être conçu comme un moyen d'utiliser du code hérité et/ou tiers avec votre beau code Spring flambant neuf. C'est du moins ce que j'ai retenu de la documentation.

2
extraneon