Est-ce une bonne ou une mauvaise idée de faire revenir les setters en java "this"?
public Employee setName(String name){
this.name = name;
return this;
}
Ce modèle peut être utile car vous pouvez alors enchaîner des setters comme ceci:
list.add(new Employee().setName("Jack Sparrow").setId(1).setFoo("bacon!"));
au lieu de cela:
Employee e = new Employee();
e.setName("Jack Sparrow");
...and so on...
list.add(e);
... mais cela va en quelque sorte à l'encontre de la convention standard. Je suppose que cela pourrait valoir la peine simplement parce que cela peut faire que le setter fasse autre chose d'utile. J'ai vu ce modèle utilisé à certains endroits (par exemple JMock, JPA), mais il semble rare, et n'est généralement utilisé que pour des API très bien définies où ce modèle est utilisé partout.
Mettre à jour:
Ce que j'ai décrit est évidemment valable, mais ce que je recherche vraiment, ce sont des réflexions sur la question de savoir si cela est généralement acceptable et s'il y a des écueils ou des meilleures pratiques connexes. Je connais le modèle Builder mais il est un peu plus impliqué que ce que je décris - comme Josh Bloch le décrit, il existe une classe Builder statique associée pour la création d'objets.
la source
this
. Parfois, je modifie même la fonction de sorte qu'au lieu de renvoyer une valeur, elle opère sur un membre de l'objet, juste pour que je puisse le faire. C'est merveilleux. :)Réponses:
Je ne pense pas qu'il y ait quelque chose de mal en particulier, c'est juste une question de style. C'est utile lorsque:
Des alternatives à cette méthode pourraient être:
Si vous ne définissez que quelques propriétés à la fois, je dirais que cela ne vaut pas la peine de retourner «ceci». Cela tombe certainement si vous décidez plus tard de renvoyer autre chose, comme un indicateur de statut / succès / message.
la source
Ce n'est pas une mauvaise pratique. C'est une pratique de plus en plus courante. La plupart des langages ne vous obligent pas à traiter l'objet retourné si vous ne le souhaitez pas, il ne modifie donc pas la syntaxe d'utilisation du setter "normal" mais vous permet de chaîner les setters ensemble.
Ceci est communément appelé un modèle de générateur ou une interface fluide .
Il est également courant dans l'API Java:
la source
bla.foo.setBar1(...) ; bla.foo.setBar2(...)
lorsque vous pouviez écrirebla.foo /* newline indented */.setBar1(...) /* underneath previous setter */ .setBar2(...)
(ne peut pas utiliser les sauts de ligne dans un commentaire SO comme celui-ci :-( ... j'espère que vous obtenez le point en considérant 10 de ces setters ou des appels plus complexes)Résumer:
Quelques autres points non mentionnés:
Cela viole le principe selon lequel chaque fonction doit faire une (et une seule) chose. Vous pouvez ou non y croire, mais en Java, je pense que cela fonctionne bien.
Les IDE ne vont pas les générer pour vous (par défaut).
J'ai enfin, voici un point de données du monde réel. J'ai eu des problèmes avec une bibliothèque construite comme ça. Le générateur de requêtes d'Hibernate en est un exemple dans une bibliothèque existante. Étant donné que les méthodes set * de Query renvoient des requêtes, il est impossible de dire simplement en regardant la signature comment l'utiliser. Par exemple:
Il introduit une ambiguïté: la méthode modifie-t-elle l'objet actuel (votre modèle) ou, peut-être que Query est vraiment immuable (un modèle très populaire et précieux), et la méthode en renvoie un nouveau. Cela rend la bibliothèque plus difficile à utiliser et de nombreux programmeurs n'exploitent pas cette fonctionnalité. Si les colons étaient des colons, il serait plus clair de les utiliser.
la source
this
n'est guère compliqué. :-)Je préfère utiliser les méthodes «avec» pour cela:
Donc:
Attention : cette
withX
syntaxe est couramment utilisée pour fournir des "setters" pour les objets immuables, donc les appelants de ces méthodes peuvent raisonnablement s'attendre à ce qu'ils créent de nouveaux objets plutôt que de muter l'instance existante. Peut-être qu'une formulation plus raisonnable serait quelque chose comme:Avec la convention de nommage chainsetXyz (), tout le monde devrait être content.
la source
get
, unset
et unwith
pour chaque champ de classe. C'est toujours une solution intéressante. :)Project Lombok
des »@Getter/@Setter
annotations ... ce serait fantastique pour chaîner. Ou vous pouvez utiliser quelque chose qui ressemble beaucoup auKestrel
combinateur ( github.com/raganwald/Katy ) utilisé par les démons JQuery et Javascript.with
préfixe est une convention différente. comme @qualidafial a donné un exemple. les méthodes préfixéeswith
ne doivent pas renvoyerthis
mais plutôt une nouvelle instance comme l'instance actuelle maiswith
qui changent. Cela se fait lorsque vous souhaitez que vos objets soient immuables. Donc, quand je vois une méthode préfixée,with
je suppose que j'obtiendrai un nouvel objet, pas le même objet.Si vous ne voulez pas revenir
'this'
du setter mais ne voulez pas utiliser la deuxième option, vous pouvez utiliser la syntaxe suivante pour définir les propriétés:En passant, je pense que c'est légèrement plus propre en C #:
la source
equals
méthode. Il existe des moyens très simples de gérer les classes anonymesequals
si vous savez ce que vous faites.Il rompt non seulement la convention des getters / setters, il rompt également le cadre de référence de la méthode Java 8.
MyClass::setMyValue
est unBiConsumer<MyClass,MyValue>
, etmyInstance::setMyValue
est unConsumer<MyValue>
. Si vous avez votre retour de setterthis
, alors ce n'est plus une instance valide deConsumer<MyValue>
, mais plutôt unFunction<MyValue,MyClass>
, et provoquera la rupture de tout ce qui utilisant des références de méthode à ces setters (en supposant qu'il s'agit de méthodes void).la source
Consumer<A>
etFunction<A,B>
en fournissant une implémentation par défaut devoid accept(A a) { apply(a); }
. Ensuite, il peut facilement être utilisé comme l'un ou l'autre et ne cassera aucun code qui nécessite un formulaire spécifique.Je ne connais pas Java mais je l'ai fait en C ++. D'autres personnes ont dit que cela rend les lignes très longues et très difficiles à lire, mais je l'ai fait comme ça plusieurs fois:
C'est encore mieux:
du moins, je pense. Mais vous êtes les bienvenus pour me downvote et appelez-moi un horrible programmeur si vous le souhaitez. Et je ne sais pas si vous êtes autorisé à le faire même en Java.
la source
//
après chaque méthode si vous configurez votre IDE pour ne pas joindre les lignes déjà encapsulées (par exemple Eclipse> Propriétés> Java> Style de code> Formateur> Line Wrapping> Ne jamais joindre les lignes déjà encapsulées).Ce schéma (jeu de mots voulu), appelé «interface fluide», devient très populaire maintenant. C'est acceptable, mais ce n'est pas vraiment ma tasse de thé.
la source
Parce qu'il ne retourne pas void, ce n'est plus un setter de propriétés JavaBean valide. Cela peut être important si vous êtes l'une des sept personnes dans le monde à utiliser les outils visuels "Bean Builder", ou l'une des 17 à l'aide des éléments JSP-bean-setProperty.
la source
Au moins en théorie , cela peut endommager les mécanismes d'optimisation de la JVM en définissant de fausses dépendances entre les appels.
Il est censé être du sucre syntaxique, mais peut en fait créer des effets secondaires dans la machine virtuelle du Java 43 super intelligent.
C'est pourquoi je vote non, ne l'utilisez pas.
la source
set
méthode dépend de la premièreset
méthode bien qu'il soit connu du programmeur.-XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining
Le jdk java7 intègre définitivement les méthodes chaînées, et fait environ le même nombre d'itérations qu'il faut pour marquer les setters vides comme chauds et les aligner aussi. Il me semble que vous sous-estimez la puissance des algorithmes d'élagage d'opcode de la JVM; s'il sait que vous retournez ceci, il sautera l'opcode jrs (java return statement) et le laissera simplement sur la pile.Ce n'est pas du tout une mauvaise pratique. Mais ce n'est pas compatible avec JavaBeans Spec .
Et il y a beaucoup de spécifications qui dépendent de ces accesseurs standard.
Vous pouvez toujours les faire coexister les uns avec les autres.
Maintenant, nous pouvons les utiliser ensemble.
Voici une autre version pour objet immuable.
Maintenant, nous pouvons le faire.
la source
some
champ. En second lieu , vous devez ajouter une sauvegarde et un ensemblesome
ànull
en construction () doncSome
est vraiment immuable, sinon vous pourriez appelerbuilder.value()
sur la même instance Builder à nouveau. Et enfin, oui, vous avez un constructeur, mais vous avezSome
toujours un constructeur public, ce qui signifie que vous ne préconisez pas ouvertement l'utilisation du constructeur, c'est-à-dire que l'utilisateur n'en sait rien autrement qu'en essayant ou en recherchant une méthode pour définir une coutumevalue
du tout.Si vous utilisez la même convention dans toute l'application, cela semble bien.
D'un autre côté, si une partie existante de votre application utilise une convention standard, je m'en tiendrai et ajouterai des constructeurs à des classes plus complexes
la source
Paulo Abrantes offre une autre façon de rendre les setters JavaBean fluides: définir une classe de générateur interne pour chaque JavaBean. Si vous utilisez des outils qui sont déconcertés par des setters qui retournent des valeurs, le modèle de Paulo pourrait vous aider.
la source
Je suis en faveur du retour des setters. Je m'en fiche si ce n'est pas compatible avec les haricots. Pour moi, si c'est correct d'avoir l'expression / l'instruction "=", alors les setters qui retournent des valeurs sont très bien.
la source
J'avais l'habitude de préférer cette approche mais je l'ai décidée.
Les raisons:
Le modèle Builder que j'ai vu n'utilise pas la convention setFoo (foo) .setBar (bar) mais plus foo (foo) .bar (bar). Peut-être exactement pour ces raisons.
C'est, comme toujours, une question de goût. J'aime bien l'approche des "moindres surprises".
la source
Ce modèle particulier est appelé chaînage de méthodes. Lien Wikipédia , cela a plus d'explications et d'exemples sur la façon dont cela se fait dans divers langages de programmation.
PS: J'ai juste pensé à le laisser ici, car je cherchais le nom spécifique.
la source
À première vue: "horrible!".
Après réflexion
est en fait moins sujet aux erreurs que
Tellement intéressant. Ajout d'une idée à la trousse à outils ...
la source
list
au départ.Oui, je pense que c'est une bonne idée.
Si je pouvais ajouter quelque chose, qu'en est-il de ce problème:
Cela fonctionnera:
Cela ne sera pas accepté par Eclipse! :
En effet, setName () renvoie un People et non un Friend, et il n'y a pas PeoplesetNickName.
Comment pourrions-nous écrire des setters pour renvoyer la classe SELF au lieu du nom de la classe?
Quelque chose comme ça serait bien (si le mot-clé SELF existait). Est-ce que cela existe de toute façon?
la source
class C<S extends C<S>>
, ce qui est plus sûr qu'un simpleS extends C
. a) SiA extends B
, etB extends C<B>
, et vous avez un A, vous savez seulement qu'un B est renvoyé à moins que A ne remplace chaque méthode. b) Vous ne pouvez pas désigner un local, non brutC<C<C<C<C<...>>>>>
.En général, c'est une bonne pratique, mais pour les fonctions de type ensemble, vous devrez peut-être utiliser le type booléen pour déterminer si l'opération s'est terminée avec succès ou non, c'est une façon également. En général, il n'y a pas de dogme pour dire que c'est bon ou lit, ça vient de la situation, bien sûr.
la source
De la déclaration
je vois deux choses
1) Déclaration vide de sens. 2) Manque de lisibilité.
la source
Cela peut être moins lisible
ou ca
C'est bien plus lisible que:
la source
Je fais mes setters depuis un bon moment et le seul vrai problème est avec les bibliothèques qui collent avec les getPropertyDescriptors stricts pour obtenir les accesseurs de bean reader / writer bean. Dans ces cas, votre "bean" java n'aura pas les écrivains que vous attendez.
Par exemple, je ne l'ai pas testé à coup sûr, mais je ne serais pas surpris que Jackson ne les reconnaisse pas comme des setters lors de la création d'objets Java à partir de json / maps. J'espère que je me trompe sur celui-ci (je le testerai bientôt).
En fait, je développe un ORM SQL centré léger et je dois ajouter du code au-delà de getPropertyDescriptors aux setters reconnus qui le retournent.
la source
Il y a longtemps, répondez, mais mes deux cents ... C'est bien. Je souhaite que cette interface fluide soit utilisée plus souvent.
La répétition de la variable «usine» n'ajoute pas plus d'informations ci-dessous:
C'est plus propre, à mon humble avis:
Bien sûr, comme l'une des réponses déjà mentionnées, l'API Java devrait être modifiée pour le faire correctement dans certaines situations, comme l'héritage et les outils.
la source
Il est préférable d'utiliser d'autres constructions de langage si elles sont disponibles. Par exemple, dans Kotlin, vous utilisez avec , appliquez ou laissez . Si vous utilisez cette approche, vous n'aurez pas vraiment besoin de renvoyer une instance de votre setter.
Cette approche permet à votre code client d'être:
Voici quelques exemples.
la source
Si j'écris une API, j'utilise "return this" pour définir des valeurs qui ne seront définies qu'une seule fois. Si j'ai d'autres valeurs que l'utilisateur devrait pouvoir changer, j'utilise plutôt un setter vide standard.
Cependant, c'est vraiment une question de préférence et le chaînage des setters a l'air plutôt cool, à mon avis.
la source
Je suis d'accord avec toutes les affiches affirmant que cela rompt avec les spécifications JavaBeans. Il y a des raisons de préserver cela, mais je pense également que l'utilisation de ce modèle de générateur (auquel il a été fait allusion) a sa place; tant qu'il n'est pas utilisé partout, il doit être acceptable. "It's Place", pour moi, est l'endroit où le point final est un appel à une méthode "build ()".
Il existe bien sûr d'autres façons de définir toutes ces choses, mais l'avantage ici est qu'il évite 1) les constructeurs publics à plusieurs paramètres et 2) les objets partiellement spécifiés. Ici, le générateur collecte ce qui est nécessaire, puis appelle son "build ()" à la fin, ce qui peut garantir qu'un objet partiellement spécifié n'est pas construit, car cette opération peut bénéficier d'une visibilité inférieure à la visibilité publique. L'alternative serait des "objets paramètres", mais cette IMHO ne fait que repousser le problème d'un niveau.
Je n'aime pas les constructeurs à plusieurs paramètres car ils rendent plus probable la transmission de nombreux arguments de même type, ce qui peut faciliter la transmission des mauvais arguments aux paramètres. Je n'aime pas utiliser beaucoup de setters car l'objet pourrait être utilisé avant qu'il ne soit entièrement configuré. De plus, la notion d'avoir des valeurs par défaut basées sur des choix précédents est mieux servie avec une méthode "build ()".
En bref, je pense que c'est une bonne pratique, si elle est utilisée correctement.
la source
Mauvaise habitude: un setter définit un getter get
qu'en déclarant explicitement une méthode, cela le fait pour U
la source