Les Getters et les setters sont souvent critiqués comme étant des OO non appropriés. D'autre part, la plupart du code OO que j'ai vu possède de nombreux accesseurs et régleurs.
Quand les getters et les setters sont-ils justifiés? Essayez-vous d'éviter de les utiliser? Sont-ils surutilisés en général?
Si votre langue préférée a des propriétés (la mienne), de telles choses sont également considérées comme des accesseurs pour la question. Ils sont la même chose du point de vue de la méthodologie OO. Ils ont juste une syntaxe plus agréable.
Sources de critiques Getter / Setter (certaines tirées de commentaires pour leur donner une meilleure visibilité):
- http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html
- http://typicalprogrammer.com/?p=23
- http://c2.com/cgi/wiki?AccessorsAreEvil
- http://www.darronschall.com/weblog/2005/03/no-brain-getter-and-setters.cfm
- http://www.adam-bien.com/roller/abien/entry/encapsulation_violation_with_getters_and
- http://www.yegor256.com/2014/09/16/getters-and-setters-are-evil.html
Pour énoncer la critique simplement: Les Getters et Setters vous permettent de manipuler l’état interne des objets de l’extérieur. Cela viole l’encapsulation. Seul l'objet lui-même doit se soucier de son état interne.
Et un exemple de version procédurale du code.
struct Fridge
{
int cheese;
}
void go_shopping(Fridge fridge)
{
fridge.cheese += 5;
}
Version mutatrice du code:
class Fridge
{
int cheese;
void set_cheese(int _cheese) { cheese = _cheese; }
int get_cheese() { return cheese; }
}
void go_shopping(Fridge fridge)
{
fridge.set_cheese(fridge.get_cheese() + 5);
}
Les getters et les setters ont rendu le code beaucoup plus compliqué sans permettre une encapsulation correcte. Parce que l'état interne est accessible à d'autres objets, nous n'avons pas beaucoup à gagner en ajoutant ces accesseurs et ces setters.
La question a déjà été discutée sur Stack Overflow:
la source
Getters and setters are often criticized as being not proper OO
- Citation, s'il te plaît.Réponses:
Avoir des getters et des setters ne rompt pas en soi l'encapsulation. Ce qui ne fonctionne pas, c’est l’ajout automatique d’un getter et d’un setter pour chaque membre de données (chaque champ , en java lingo), sans y penser. Bien que cela soit mieux que de rendre tous les membres des données publiques, cela n’est qu’à un petit pas.
Le but de l'encapsulation n'est pas que vous ne devriez pas pouvoir savoir ou changer l'état de l'objet de l'extérieur de l'objet, mais que vous devriez avoir une politique raisonnable pour le faire.
Certains membres de données peuvent être entièrement internes à l'objet et ne doivent avoir ni getters ni setters.
Certains membres de données doivent être en lecture seule. Ils peuvent donc avoir besoin de getters, mais pas de setters.
Certains membres de données devront peut-être rester cohérents les uns avec les autres. Dans un tel cas, vous ne fourniriez pas de paramètre pour chacun, mais une méthode unique pour les configurer en même temps, afin de pouvoir vérifier la cohérence des valeurs.
Il est possible que certains membres de données ne doivent être modifiés que d'une certaine manière, par exemple incrémentés ou décrémentés d'un montant fixe. Dans ce cas, vous fourniriez une méthode
increment()
et / ou unedecrement()
méthode plutôt qu'un paramètre.D'autres encore peuvent avoir besoin d'être en lecture-écriture et auraient à la fois un getter et un setter.
Considérons un exemple de
class Person
. Supposons qu'une personne ait un nom, un numéro de sécurité sociale et un âge. Disons que nous ne permettons pas aux gens de changer leur nom ou leur numéro de sécurité sociale. Cependant, l'âge de la personne devrait être incrémenté de 1 chaque année. Dans ce cas, vous devez fournir un constructeur qui initialise le nom et le SSN sur les valeurs données et initialise l'âge à 0. Vous fournissez également une méthodeincrementAge()
permettant d'augmenter l'âge de 1. Vous indiquez également Getters pour les trois. Aucun ajusteur n'est requis dans ce cas.Dans cette conception, vous permettez à l'état de l'objet d'être inspecté de l'extérieur de la classe, et vous permettez qu'il soit modifié de l'extérieur de la classe. Cependant, vous ne permettez pas que l'état soit modifié de manière arbitraire. Il existe une politique qui stipule en effet que le nom et le SSN ne peuvent pas être modifiés du tout et que l'âge peut être incrémenté d'une année à la fois.
Maintenant, disons qu'une personne a aussi un salaire. Et les gens peuvent changer d'emploi à leur guise, ce qui signifie que leur salaire va également changer. Pour modéliser cette situation, nous n'avons pas d'autre moyen que de fournir une
setSalary()
méthode! Permettre que le salaire soit modifié à volonté est une politique parfaitement raisonnable dans ce cas.En passant, dans votre exemple, je donnerais à la classe
Fridge
les méthodesputCheese()
andtakeCheese()
, au lieu deget_cheese()
etset_cheese()
. Ensuite, vous auriez toujours l'encapsulation.la source
La raison fondamentale pour les accesseurs en Java est très simple:
Par conséquent, si vous souhaitez permettre à un champ de passer à travers l'interface, vous aurez besoin d'un lecteur et d'une méthode d'écriture. Celles-ci s'appellent traditionnellement getX et setX pour le champ x.
la source
De http://www.adam-bien.com/roller/abien/entry/encapsulation_violation_with_getters_and
Style JavaBean:
OO-style:
Eh bien, je préfère clairement la dernière approche; elle ne saigne pas les détails de l'implémentation, elle est plus simple et plus concise et toutes les informations nécessaires sont incluses dans l'appel de méthode. Il est donc plus facile de les comprendre correctement. Je préfère également définir des membres privés à l'aide de paramètres dans le constructeur, dans la mesure du possible.
Votre question est la suivante: quand un getter / setter est-il justifié? Peut-être lorsqu'un changement de mode est nécessaire ou que vous devez interroger un objet pour obtenir des informations.
En y réfléchissant, lorsque j'ai commencé à coder en C #, j'ai écrit beaucoup de code dans le style Javabeans illustré ci-dessus. Mais au fur et à mesure que j'ai acquis de l'expérience dans la langue, j'ai commencé à définir davantage de membres dans le constructeur et à utiliser des méthodes qui ressemblaient davantage au style OO ci-dessus.
la source
Lorsque les comportements "get" et "set" correspondent en réalité au comportement de votre modèle, ce qui n'est pratiquement jamais .
Toute autre utilisation n’est qu’une fraude, car le comportement du domaine métier n’est pas clair.
Modifier
Cette réponse aurait peut-être semblé désinvolte, alors permettez-moi de développer. Les réponses ci-dessus sont pour la plupart correctes, mais nous nous concentrons sur les paradigmes de programmation de la conception orientée objet et sur ce qui manque vraiment. D'après mon expérience, cela amène les gens à penser qu'éviter les gettings et les setters est une règle académique pour les langages de programmation OO (par exemple, les gens pensent que remplacer des getters par des propriétés est une tâche fastidieuse)
En fait, c'est une conséquence du processus de conception. Il n'est pas nécessaire d'entrer dans les interfaces, l'encapsulation et les modèles, en se demandant si cela enfreint ou non ces paradigmes et ce qui constitue ou non une bonne programmation OO. Le seul point qui compte finalement est que, si rien dans votre domaine ne fonctionne de la sorte en les plaçant dans, vous ne modélisez pas votre domaine.
En réalité, il est hautement improbable qu'un système de votre domaine ait des accesseurs. Vous ne pouvez pas vous adresser à l'homme ou à la femme responsable de la paie et simplement dire "Réglez ce salaire sur X" ou "Recevez-moi ce salaire" . Un tel comportement n'existe tout simplement pas
Si vous mettez cela dans votre code, vous ne concevez pas votre système pour qu'il corresponde au modèle de votre domaine. Oui, ça casse les interfaces et l'encapsulation, mais ce n'est pas la question. Le fait est que vous modélisez quelque chose qui n'existe pas.
De plus, il vous manque probablement une étape ou un processus important, car il y a probablement une raison pour laquelle je ne peux pas me contenter de payer et de dire de fixer ce salaire à X.
Quand les gens utilisent des accesseurs et des passeurs, ils ont tendance à pousser les règles de ce processus au mauvais endroit. Cela s'éloigne encore plus de votre domaine. En utilisant l’exemple du monde réel, c’est comme un salaire en supposant que la personne aléatoire qui entre est autorisée à obtenir ces valeurs, sinon elle ne les demanderait pas. Non seulement ce n'est pas ainsi que le domaine est, mais il ment en fait sur la façon dont le domaine est.
la source
set/get
salaire?En règle générale, les getters et les setters sont une mauvaise idée. Si un champ ne fait pas logiquement partie de l'interface et que vous le rendez privé, c'est bien. Si cela fait logiquement partie de l'interface et que vous le rendez public, c'est bien. Mais si vous le rendez privé, puis que vous vous retournez et le rendez effectivement public à nouveau en fournissant un getter et un setter, vous revenez à votre point de départ sauf que votre code est maintenant plus détaillé et plus obscur.
Évidemment, il y a des exceptions. En Java, vous devrez peut-être utiliser des interfaces. La bibliothèque standard Java a des exigences de compatibilité ascendante si extrêmes qu’elles dépassent les mesures normales de la qualité du code. Il est même possible que vous traitiez réellement le cas légendaire mais rare où il y a de bonnes chances que vous remplaciez ultérieurement un champ stocké par un calcul à la volée sans casser l'interface. Mais ce sont des exceptions. Getters et setters sont un anti-modèle qui nécessite une justification spéciale.
la source
que le champ soit accessible directement ou par la méthode n'est pas vraiment important.
Les invariants de classe (utiles) sont importants. Et pour les préserver, nous avons parfois besoin de ne pas pouvoir changer quelque chose de l'extérieur. Par exemple. si nous avons la classe Square avec une largeur et une hauteur séparées, changer l’une d’elles en fait une place autre que carrée. Nous avons donc besoin de la méthode changeSide Si c'était Rectangle, nous pourrions avoir un champ setters / public. Mais un testeur vérifierait si sa valeur supérieure à zéro serait meilleure.
Et dans des langages concrets (par exemple, Java), il existe des raisons pour lesquelles nous avons besoin de ces méthodes (interfaces). Et une autre raison de la méthode est la compatibilité (source et binaire). Il est donc plus facile de les ajouter, puis de se demander si un champ public suffirait.
btw. J'aime utiliser des classes de valeurs immuables simples avec des champs finaux publics.
la source
Vous voudrez peut-être modifier vos éléments internes en changeant les interfaces tout en conservant les mêmes. Si vos interfaces ne varient pas, votre code ne cassera pas. Vous pouvez toujours changer vos internes comme vous le souhaitez.
la source
Mon approche est la suivante -
Lorsque je compte utiliser les données plus tard, un getter / setter est justifié. De plus, si des changements surviennent, j’insère souvent les données dans un getter / setter.
Si c'est une structure POD, je laisse les créneaux disponibles.
Sur un plan plus abstrait, la question est "qui gère les données", et cela dépend du projet.
la source
Si utiliser des accesseurs et des setters semble compliqué, le problème pourrait être la langue, pas le concept lui-même.
Voici le code du deuxième exemple écrit en Ruby:
Notez que cela ressemble beaucoup au premier exemple en Java? Lorsque les accesseurs et les régleurs sont traités comme des citoyens de premier ordre, ils ne constituent pas une corvée et la flexibilité supplémentaire peut parfois être une véritable aubaine. Par exemple, nous pourrions décider de renvoyer une valeur par défaut pour le fromage sur un nouveau réfrigérateur:
Bien sûr, il y aura beaucoup de variables qui ne devraient pas du tout être exposées publiquement. Exposer inutilement des variables internes aggravera votre code, mais vous pouvez difficilement blâmer cela pour les getters et les setters.
la source
Prenons une
Size
classe qui englobe la largeur et la hauteur. Je peux éliminer les setters en utilisant le constructeur, mais en quoi cela m'aide-t-il à dessiner un rectangleSize
? La largeur et la hauteur ne sont pas des données internes à la classe; ce sont des données partagées qui doivent être disponibles pour les consommateurs de Size.Les objets sont constitués de comportements et d’états ou d’attributs. S'il n'y a pas d'état exposé, seuls les comportements sont publics.
Sans état, comment trieriez-vous une collection d'objets? Comment rechercheriez-vous une instance spécifique d'un objet? Si vous utilisez uniquement des constructeurs, que se passe-t-il lorsque votre objet possède une longue liste d'attributs?
Aucun paramètre de méthode ne doit être consommé sans validation. C'est donc par paresse d'écrire:
Si vous écrivez de cette façon, vous vous êtes au moins préparé à utiliser le setter pour la validation; c'est mieux qu'un terrain public - mais à peine. Mais au moins, vous avez une interface publique cohérente sur laquelle vous pouvez revenir et mettre des règles de validation sans enfreindre le code de vos clients.
Getters, setters, properties, mutators, appelez-les comme vous voulez, mais ils sont nécessaires.
la source
int
variable d'instance, par exemple, et imaginez que vous décidiez d'ajouter une règle de validation pour n'accepter que des valeurs non négatives. Le problème est que le code de votre client peut déjà compter sur la possibilité de lui attribuer une valeur négative ...Si les getters et les setters violent l’encapsulation et le vrai OO, alors je suis sérieusement en difficulté
J'ai toujours senti qu'un objet représentait tout ce qui vous venait à l'esprit et dont vous aviez besoin.
Je viens de finir d'écrire un programme qui génère des labyrinthes en Java, et j'ai une classe qui représente les "carrés de labyrinthe". J'ai des données dans cette classe qui représentent des coordonnées, des murs et des booléens, etc.
Je dois avoir un moyen de changer / manipuler / accéder à ces données! Qu'est-ce que je fais sans les geters et les setters? Java n'utilise pas les propriétés et la définition de toutes mes données locales de cette classe sur public constitue DEFINITIVEMENT une violation de l'encapsulation et de OO.
la source
Premièrement, il existe en gros deux types d’objets que je commenterai, les types de valeur et de service.
Les types de services ne devraient jamais avoir de paramètres, les dépendances dont ils ont besoin ne devraient pas être négligeables. Le meilleur moyen de passer des dépendances est de passer par un constructeur ou une fabrique, de sorte que toutes les instances soient entièrement formées dès le début, de manière claire et simple.
Les types de valeur doivent également être immuables. D'un autre côté, il peut arriver que ce ne soit pas pratique, comme un ORM, ou un autre mappage, par exemple d'un widget à un objet. Tous les autres types de valeur transmis dans le système d'une couche ou d'une partie à une autre doivent être immuables et ne doivent pas comporter de paramètres.
la source
Un Getter / Setter est justifié comme n'importe quelle autre méthode publique. La justification est principalement parce que nous voulons fournir une interface vers le monde extérieur qui définit la manière dont notre classe interagit avec d'autres classes. Nous le faisons principalement parce que nous voulons réduire le couplage entre entités distinctes. Réduire le couplage est une bonne chose pour plusieurs raisons:
la source
Oui, les getters et les setters sont un anti-modèle dans la programmation orientée objet et ne doivent jamais être utilisés: http://www.yegor256.com/2014/09/16/getters-and-setters-are-evil.html . En un mot, ils ne rentrent pas dans le paradigme orienté objet car ils vous incitent à traiter un objet comme une structure de données. Ce qui est une idée fausse majeure.
la source
J'espère que tout ce que l'EDI développé par la société qui développe votre langage de programmation généré automatiquement n'enfreint pas les "Principes d'orientation de l'objet".
Cela étant dit, chaque fois que vous avez une variable de portée publique, utilisez un getter et un setter et vous êtes en or. Cela me semble être l’élément nécessaire du principe d’encapsulation extrêmement orienté objet, même s’il ressemble à beaucoup de code.
La raison de les utiliser est que l'encapsulation appropriée peut encore avoir lieu et tant que vous avez extrait le calque qui permet à la personne qui manipule votre objet de sentir votre objet, vous pouvez l'enlever sans même le savoir.
Qu'il suffise de dire, une maison divisée ne peut subsister, l'un des locataires de OO ne va pas s'enflammer et vous ne pouvez pas servir à la fois l'encapsulation et l'optimisation prématurée.
la source
Je pensais que nous aurions des réponses plus habituelles ici?
Les Getters et les setters sont généralement extrêmement efficaces (quiconque dit autre chose a tort, aussi simple que cela).
Bien que vous deviez vous rappeler de ne pas avoir trop d'ingénieur, ne faites jamais un getter ou un setter inutile. Toute information que vous n'allez pas utiliser par une autre classe et pour laquelle vous ne devriez avoir aucun getter ou setter.
Cependant, la raison pour laquelle vous ne rendez pas les champs publics et que vous avez plutôt des accesseurs et des setters sont principalement:
Il n'est pas possible de faire des tests appropriés en utilisant des champs. Les Getters / setters sont bien meilleurs à cet égard.
Il est impossible d'utiliser correctement les champs dans un contexte de programmation en temps réel. Getters / setters synchronisés est la voie à suivre.
Le sujet de l'interface (déjà expliqué donc je ne le ferai pas).
Il est plus facile à utiliser lorsque vous réutilisez correctement le système.
Il est beaucoup plus difficile de savoir quelles classes utilisent votre classe et ce qui se brisera si vous changez de champ plutôt qu'un getter / setter.
Par conséquent, le seul moment où vous utilisez un champ public au lieu d’un getter / setter, c’est quand vous ne créez pas de projet officiel, mais que vous le faites simplement pour le plaisir et que vous ne pouvez pas vous soucier du getter / setters.
la source