5
votes

Un membre de classe immuable doit-il avoir une méthode d'accesseur ou être autorisé à être public?

J'ai une question sur les meilleures pratiques de conception. J'ai essayé de créer plus de composants immuables dans mon projet parce que j'ai lu qu'ils étaient plus faciles à maintenir à long terme et que je voulais tester cela.

Lorsque vous avez une classe avec des données membres immuables, dites

 public/private final int importantNumber = 3;

Si le int est toujours déclaré comme privé et doté d'une méthode d'accesseur, ou parce que ses finals, qu'est-ce la difficulté de permettre l'accès direct et de le rendre public? Je ne vois aucun problème avec le fait qu'il soit rendu public car vous ne pouvez pas le modifier.

Dans mon cas, l'objet immuable est créé avec des valeurs qui lui sont transmises, puis remplit automatiquement les autres à partir d'une base de données, tout étant définitif.

Ou est-ce simplement une question de préférence et déclenchera une guerre de religion? Comme il y a beaucoup de questions sur l'accès au membre de données depuis l'intérieur de la classe, je tiens à préciser que je pose la question à une autre classe externe qui tente d'obtenir la valeur.


7 commentaires

une méthode accesseur a la possibilité de contenir plus de logique (calculs et ainsi de suite), alors que le champ ne le fait pas, l'utilisation d'une méthode permet également de renommer le champ (car il n'est utilisé qu'en interne)


Voir stackoverflow.com/questions/1568091/…


J'utiliserais toujours un getter, car il permet de se moquer facilement des tests unitaires.


@NeplatnyUdaj Mais cela pourrait être "paquet protégé". S'il est public, vous n'avez aucun contrôle sur qui d'autre l'appellera, au moins avant Java 9 et les modules.


Ce que je voulais dire, c'est qu'avec un cadre de test comme mockito, je n'ai pas besoin de créer une instance réelle (ce qui peut être encombrant) lorsque j'ai besoin de se moquer d'une seule valeur.


@GhostCat Votre point était mort, je ne pensais qu'à l'ici et à moi, je n'avais pas pensé à qui pourrait utiliser le code plus tard. Le but est de faciliter la maintenance, alors même si je me moque des getters qui retournent une valeur et ne font rien d'autre, ils ont leur place. C'est dommage qu'il n'y ait pas de mot-clé que je puisse inclure qui me permette de déclarer un psudo-scope et un nom pour un getter. private int importantNumber (public getImportantNumber) = 3; Ensuite, si nécessaire, je peux simplement définir le getter plus tard.


Je pense que d'autres langages vont dans cette direction, mais hélas, c'est Java, passe-partout est ton nom.


3 Réponses :


5
votes

Rendre les choses publiques permet à d'autres codes de s'en servir.

Peu importe si les données sont mutables ou immuables. Dès qu'un autre code se rend dépendant de ces informations, vous activez les problèmes futurs. Et dans tout projet plus vaste, ces problèmes se manifesteront tôt ou tard.

Rendre les choses publiques, tout d'un coup, les détails d'implémentation (internes) peuvent s'infiltrer dans d'autres codes! Et bien sûr: si ces données sont mutables, cela ouvre juste une vraie boîte de vers.

Mais même un simple if (someObject.someField == peu importe) puis faire ceci sinon faire cela peut rapidement devenir un énorme problème. Supposons simplement que vous ayez ce code à 10, 50, 100 endroits différents dans votre énorme projet.

Ainsi, votre règle par défaut est la suivante: masquez vos informations. Rendre les choses publiques est l ' exception , cela se produit parce que vous voulez absolument que votre design le soit. Votre défaut est de donner à vos champs (et même à vos méthodes) la visibilité la plus restrictive qui vous permette toujours de mettre en œuvre vos exigences.

Et notez: il est juste "légèrement" préférable de cacher le champ et d'avoir une méthode d'accesseur pour cela. Parce que if (someObject.someMethod () == ...) conduit aux mêmes problèmes. Et (presque) pire: maintenant vous décidez que someMethod () devrait faire quelque chose de différent, pour résoudre un problème spécifique. Mais êtes-vous sûr que les autres 99 utilisations de cet appel de méthode fonctionnent correctement avec ce changement?!

Dernière mise en garde: Java 9 a introduit le concept de module, vous pouvez donc enfin avoir quelque chose de public, mais toujours pas utilisable depuis l'extérieur de votre module. Mais c'est plus un addendum théorique, je continuerais de suivre la règle de base et de ne pas rendre les choses publiques à moins d'avoir de bonnes raisons de le faire. Si vous voulez accéder à ces informations, par exemple pour les tests unitaires, un getter protégé par paquet devrait faire l'affaire.


3 commentaires

Votre première ligne a tout dit. Je n'y ai pas pensé. J'aimerais donc avoir une structure de données appropriée à partir de C ++. Les cours sont censés être des êtres vivants, mais parfois j'ai juste besoin de quelque chose pour contenir des données.


@Fering Pour les "vraies" classes de données, les choses sont légèrement différentes. S'il s'agit "juste" d'un "enregistrement" (ou d'un bean en java), une classe simple avec des champs publics pourrait être acceptable. Jusqu'à ce que vous veniez 2 ans plus tard, et que vous trouviez que vous avez besoin d'autre chose, et que vous commenciez à retravailler tous les accès directs. J'y suis allé, j'ai fait ça.


C'est pourquoi, après avoir lu votre commentaire, je suis retourné, j'ai changé les publics en privés, ajouté des accesseurs, et maintenant retravaillé le code. Ne pas faire de haricot cependant.



0
votes

Lorsque vous déclarez un objet final qui est immuable et que personne ne peut en changer la valeur.

Mais définissez public ou privé un objet important selon le principe d'encapsulation dans la POO, que vous devez déclarer une méthode pour obtenir ce champ jusqu'à ce que plus tard, vous puissiez facilement savoir où cet objet a besoin et quelle classe a besoin de cette valeur.


1 commentaires

Votre raisonnement est faux. Mon IDE peut me dire exactement quelles sont les utilisations de x.someField ou de x.someMethod (). La seule différence est la suivante: lorsque vous exposez une méthode, vous pouvez modifier le comportement de cette méthode sans que l'appelant ne le remarque. Ce qui peut conduire à un tout autre ensemble de problèmes. Changer le code ultérieurement est quelque chose que vous essayez d'éviter ...



1
votes

Il n'y a aucune différence pratique entre avoir un champ final déclaré public ou l'avoir privé avec un getter public.

Il y a beaucoup d'arguments théoriques expliquant pourquoi il est vraiment mauvais d'avoir des champs publics, mais il n'y a en réalité aucune raison pratique de ne pas le faire. Oui, en théorie, vous pourriez changer le getter plus tard pour faire quelque chose de différent, mais vous ne le ferez probablement pas. Même si vous le souhaitez, la plupart des gens vous diront qu'un getter devrait simplement renvoyer le champ qu'il obtient sans logique supplémentaire.

Pour être plus clair, les deux options sont également fausses. Les champs ne devraient pas être publics et il ne devrait pas non plus y avoir de getter. Mais , si vous faites l'un de ceux-là, l'autre est tout aussi faux. J'espère que cela aide :)


9 commentaires

Il y en a une: vous pouvez toujours venir 3 ans plus tard et changer ce corps de méthode en lancer une nouvelle RuntimeException ("vous n'auriez pas dû appeler cette méthode, le javadoc vous l'a dit, burn mf burn"); . .. bien sûr, nous ne ferions jamais cela, n'est-ce pas.


@GhostCat Hehe :) Ne me regarde pas, ce n'était pas moi :)


@Robert Oui, l'un des articles que j'ai lus mentionnait également que les getters et les setters étaient mauvais et devraient être évités. Je ne peux pas m'empêcher de les utiliser dans tous les cas.


Je me souviens de la première fois que j'ai entendu parler de Bertrand Meyer et de martinfowler.com/bliki/UniformAccessPrinciple.html ... et j'ai pensé: oh, c'est tellement raisonnable de ne pas faire la distinction entre x.foo et x.foo () ... mais bon, 25 ans plus tard, peut-être que je deviens trop vieux pour un tel des choses.


@Fering Il existe très peu d'articles pratiques sur la façon d ' éviter les setters / getters et les objets de données en général. L'orientation objet n'est pas seulement le langage, elle a des implications plus profondes. Vous devez réfléchir au comportement commercial pour éviter d'avoir tout le temps besoin de données. J'ai quelques articles pratiques (espérons-le) sur le sujet ici: javadevguy.wordpress.com


@ RobertBräutigam Je jetterai un œil à certains des articles quand j'aurai le temps, merci pour le partage. Je sais qu'il y a beaucoup plus à OO que ce que je fais, mais j'essaie d'être meilleur que moi. J'avoue que je me suis trompé et je m'efforce de le corriger.


@Fering J'ai trouvé un de mes articles il y a quelque temps qui décrit un échange dans le monde réel pour ne pas implémenter de getter, si vous avez besoin d'exemples: javadevguy.wordpress.com/2017/03/26/...


"Il n'y a pas de différence pratique entre avoir un champ final déclaré public ou l'avoir privé avec un getter public." ... mis à part le fait que rendre public un champ immuable lie l'API à l'implémentation. Une fois distribuée, votre classe doit toujours prendre en charge ce champ, même si plus tard, une autre implémentation serait préférée. Il existe des situations dans lesquelles rendre les champs publics est la bonne chose à faire (par exemple, rendre publiques les constantes d'une classe d'énumération), mais il est toujours vrai que les rendre publics décourage les couplages lâches.


@scottb Je suis d'accord avec vous et je l'ai dit dans ma réponse. Ce que je veux dire, c'est que le rendre privé puis avoir un getter public ne résout aucun des problèmes que vous avez énumérés. Par conséquent, les deux sont tout aussi mauvais.