Pourquoi utiliser getters et setters / accessors? [fermé]
Quel est l'avantage d'utiliser getters et setters - qui n'utilisent que get et set - au lieu d'utiliser simplement les champs publics pour ces variables?
si getters et setters font plus que le simple get / set, je peux comprendre celui-ci très rapidement, mais je ne suis pas 100% clair sur la façon dont:
public String foo;
est pire que:
private String foo;
public void setFoo(String foo) { this.foo = foo; }
public String getFoo() { return foo; }
alors que le premier prend beaucoup moins de code réutilisable.
30 réponses
Il y a en fait de nombreuses bonnes raisons envisager d'utiliser des accesseurs plutôt que d'exposer directement les champs d'une classe - au-delà de l'argument de l'encapsulation et de faire les futurs changements plus facile.
voici quelques-unes des raisons pour lesquelles je suis au courant:
- Encapsulation du comportement associé à l'obtention ou à la mise en place de la propriété - cela permet des fonctionnalités supplémentaires (comme la validation) à ajouter plus facilement plus tard.
- Cacher la représentation interne de la propriété tout en exposant une propriété en utilisant une représentation alternative.
- isoler votre interface publique du changement-permettant à l'interface publique de rester constante pendant que la mise en œuvre change sans affecter les consommateurs existants.
- le Contrôle de la durée de vie et la gestion de la mémoire (élimination) sémantique de la propriété-particulièrement importante dans les environnements de mémoire non gérés (comme C++ ou Objective-C).
- fournit un point d'interception de débogage pour quand une propriété change à l'exécution - déboguer quand et où une propriété change à une valeur particulière peut être assez difficile sans cela dans certains langages.
- amélioration de l'interopérabilité avec les bibliothèques conçues pour fonctionner contre la propriété getter / setters-moquerie, La sérialisation, et WPF viennent à l'esprit.
- permettant aux héritiers de changer la sémantique de la façon dont la propriété se comporte et est exposée en supplantant les méthodes getter/setter.
- permettant la transmission du getter/setter sous forme d'expressions lambda plutôt que de valeurs.
- Getters et setters peuvent permettre différents niveaux d'accès - par exemple, l'EEG peut être publique, mais l'ensemble peut être protégé.
parce que 2 semaines (mois, années) à partir de Maintenant quand vous réalisez que votre setter doit faire plus que juste fixer la valeur, vous vous rendrez compte que la propriété a été utilisée directement dans 238 autres classes : -)
un champ public n'est pas pire qu'une paire getter/setter qui ne fait rien à part retourner le champ et lui assigner. Premièrement, il est clair que (dans la plupart des langues) il n'y a pas de différence fonctionnelle. Toute différence doit être dans d'autres facteurs, comme la maintenabilité ou la lisibilité.
un avantage souvent mentionné des couples getter/setter, n'est pas. Il y a cette prétention que vous pouvez changer la mise en œuvre et vos clients ne doivent pas être recompilés. Soi-disant, setters vous permettent d'ajouter des fonctionnalités comme la validation plus tard et vos clients n'ont même pas besoin de le savoir. Cependant, ajouter validation à un setter est un changement à ses conditions préalables, une violation du contrat précédent , qui était, tout simplement, "vous pouvez mettre n'importe quoi ici, et vous pouvez obtenir cette même chose plus tard à partir du getter".
donc, maintenant que vous avez rompu le contrat, changer chaque fichier dans la base de données est quelque chose que vous devriez vouloir faire, pas l'éviter. Si vous l'évitez, vous supposez que tout le code supposait que le contrat pour ces méthodes était différent.
si cela n'aurait pas dû être le contrat, alors l'interface permettait aux clients de mettre l'objet dans des États invalides. c'est l'exact opposé de l'encapsulation si ce champ ne pouvait pas vraiment être réglé à quoi que ce soit dès le début, pourquoi la validation n'était-elle pas là dès le début?
ce même argument s'applique à d'autres avantages supposés de ces paires pass-through getter/setter: si vous décidez plus tard de changer la valeur étant définie, vous rompez le contrat. Si vous outrepassez la fonctionnalité par défaut dans une classe dérivée, au-delà de quelques modifications inoffensives (comme la journalisation ou tout autre comportement non observable), vous violez le contrat de la classe de base. C'est une violation du principe de substituabilité de Liskov, qui est considéré comme l'un des principes de OO.
Si une classe A ces getters et setters débiles pour chaque champ, alors c'est une classe qui n'a pas d'invariants, pas de contrat . Est-ce vraiment une conception orientée objet? Si tout ce que la classe A est ces getters et setters, c'est juste un détenteur de données muet, et les détenteurs de données muet devraient ressembler à des détenteurs de données muet:
class Foo {
public:
int DaysLeft;
int ContestantNumber;
};
L'ajout de paires pass-through getter/setter à une telle classe n'ajoute aucune valeur. D'autres classes devraient fournir des des opérations, pas seulement des opérations que fields fournit déjà. C'est ainsi que vous pouvez définir et maintenir des invariants utiles.
Client : "Que puis-je faire avec un objet de cette classe?"
concepteur : "vous pouvez lire et écrire plusieurs variables."
Client : "Oh... cool, je suppose?"
il y a des raisons à utilisez getters et setters, mais si ces raisons n'existent pas, faire des couples getter/setter au nom de faux dieux d'encapsulation n'est pas une bonne chose. Les raisons valables pour faire des getters ou des setters incluent les choses souvent mentionnées comme les changements potentiels que vous pouvez faire plus tard, comme la validation ou différentes représentations internes. Ou peut-être que la valeur devrait être lisible par les clients mais non accessible en écriture (par exemple, la lecture de la taille d'un dictionnaire), donc un simple getter est un bon choix. Mais ces raisons devrait être là quand vous faites le choix, et pas seulement comme une chose potentielle que vous pourriez vouloir plus tard. C'est un exemple de YAGNI ( vous N'en aurez pas besoin ).
Beaucoup de gens parlent des avantages de getters et setters, mais je veux jouer l'avocat du diable. En ce moment, je suis en train de déboguer un très grand programme où les programmeurs ont décidé de tout faire getters et setters. Ça peut sembler sympa, mais c'est un cauchemar d'ingénierie inverse.
dites que vous regardez à travers des centaines de lignes de code et vous tombez sur ceci:
person.name = "Joe";
c'est un joli morceau de code jusqu'à ce que vous réalisiez ses un setter. Maintenant, vous suivez que compositeur et trouver qu'il définit personne.prenom, personne.nom, personne.isHuman, personne.has reallycommonfirstname, and calls person.update (), qui envoie une requête à la base de données, etc. Oh, c'est là que ta fuite de mémoire se produisait.
comprendre un élément de code local à première vue est une propriété importante de bonne lisibilité que les getters et les setters ont tendance à briser. C'est pourquoi j'essaie de les éviter quand je peux, et de minimiser ce qu'ils font quand je les utilise.
Dans un pur monde orienté objet getters et setters est un terrible anti-modèle . Lire l'article: Getters/Setters. Mal. Période . En un mot, ils encouragent les programmeurs à penser aux objets comme aux structures de données, et ce type de pensée est purement procédurale (comme dans COBOL ou C). Dans un langage orienté objet, il n'y a pas de structure de données, mais seulement des objets qui exposent le comportement (pas d'attributs/propriétés!)
vous pouvez en savoir plus à ce sujet dans la Section 3.5 de Elegant Objects (mon livre sur la programmation orientée objet).
il y a plusieurs raisons. Mon préféré est quand vous avez besoin de changer le comportement ou réguler ce que vous pouvez mettre sur une variable. Par exemple, disons que vous aviez une méthode de vitesse(vitesse int). Mais vous voulez que vous ne pouvez définir une vitesse maximale de 100. Vous feriez quelque chose comme:
public void setSpeed(int speed) {
if ( speed > 100 ) {
this.speed = 100;
} else {
this.speed = speed;
}
}
maintenant et si partout dans votre code vous utilisiez le champ public et que vous vous rendiez compte que vous avez besoin de l'exigence ci-dessus? S'amuser à dénicher tous les usages du public champ au lieu de simplement modifier votre setter.
My 2 cents :)
l'un des avantages des accesseurs et des mutateurs est que vous pouvez effectuer la validation.
par exemple, si foo
était public, je pourrais facilement le mettre à null
et alors quelqu'un d'autre pourrait essayer d'appeler une méthode sur l'objet. Mais il n'est plus là! Avec une méthode setFoo
, je pouvais m'assurer que foo
n'était jamais réglé sur null
.
Accessors et mutateurs permettent également l'encapsulation - si vous n'êtes pas censé voir la valeur une fois son ensemble (peut-être qu'il est défini dans le constructeur et ensuite utilisé par des méthodes, mais jamais censé être changé), il ne sera jamais vu par quiconque. Mais si vous pouvez permettre à d'autres classes de le voir ou de le changer, vous pouvez fournir l'accesseur et/ou le mutateur approprié.
Dépend de votre langue. Vous avez étiqueté ce" orienté objet "plutôt que" Java", donc je tiens à souligner que la réponse de ChssPly76 dépend de la langue. En Python, par exemple, il n'y a aucune raison d'utiliser getters et setters. Si vous avez besoin de changer le comportement, vous pouvez utiliser une propriété, qui enveloppe un getter et setter autour de l'accès aux attributs de base. Quelque chose comme ceci:
class Simple(object):
def _get_value(self):
return self._value -1
def _set_value(self, new_value):
self._value = new_value + 1
def _del_value(self):
self.old_values.append(self._value)
del self._value
value = property(_get_value, _set_value, _del_value)
Eh bien je veux juste ajouter que même si parfois ils sont nécessaires pour l'encapsulation et la sécurité de vos variables/objets, si nous voulons coder un programme orienté objet réel, alors nous avons besoin de arrêter D'abuser les accesseurs , parce que parfois Nous dépendons beaucoup d'eux quand n'est pas vraiment nécessaire et qui fait presque la même chose que si nous mettons les variables publiques.
je sais qu'il est un peu tard, mais je pense qu'il y a des gens qui sont intéressés par la performance.
j'ai fait un petit test de performance. J'ai écrit une classe "NumberHolder" qui contient un entier. Vous pouvez soit lire cet entier en utilisant la méthode getter
anInstance.getNumber()
ou en accédant directement au numéro en utilisant anInstance.number
. Mon programme lit le nombre 1.000.000.000 de fois, par les deux voies. Ce processus est répété cinq fois et l'heure est imprimée. J'ai a obtenu le résultat suivant:
Time 1: 953ms, Time 2: 741ms
Time 1: 655ms, Time 2: 743ms
Time 1: 656ms, Time 2: 634ms
Time 1: 637ms, Time 2: 629ms
Time 1: 633ms, Time 2: 625ms
(Temps 1 est la voie la plus directe, de Temps 2 est la de lecture)
vous voyez, le getter est (presque) toujours un peu plus rapide. Puis j'ai essayé avec différents nombres de cycles. Au lieu de 1 million, j'ai utilisé 10 millions et 0,1 million. Les résultats:
10 millions de cycles:
Time 1: 6382ms, Time 2: 6351ms
Time 1: 6363ms, Time 2: 6351ms
Time 1: 6350ms, Time 2: 6363ms
Time 1: 6353ms, Time 2: 6357ms
Time 1: 6348ms, Time 2: 6354ms
Avec 10 millions de cycles, les temps sont presque les mêmes. Voici 100 mille (0,1 million) cycles:
Time 1: 77ms, Time 2: 73ms
Time 1: 94ms, Time 2: 65ms
Time 1: 67ms, Time 2: 63ms
Time 1: 65ms, Time 2: 65ms
Time 1: 66ms, Time 2: 63ms
aussi avec différentes quantités de cycles, le getter est un peu plus rapide que la voie régulière. J'espère que cela vous a aidé.
Merci, cela a vraiment clarifié ma pensée. Maintenant voici (presque) 10 (presque) bonnes raisons de ne pas utiliser getters et setters:
- lorsque vous réalisez que vous devez faire plus que simplement définir et obtenir la valeur, vous pouvez simplement rendre le champ privé, qui vous dira instantanément où vous y avez directement accédé.
- toute validation que vous effectuez dans Il ne peut y avoir de contexte libre, dont la validation est rarement dans pratique.
- vous pouvez changer la valeur étant réglée - c'est un cauchemar absolu quand l'appelant Vous passe une valeur qu'ils [choc horreur] veulent que vous stockez comme est.
- vous pouvez cacher la représentation interne-fantastique, donc vous vous assurez que toutes ces opérations sont symétriques Non?
- vous avez protégé votre interface publique des changements sous les feuilles - si vous conceviez une interface et n'étiez pas sûr si l'accès direct à quelque chose était OK, alors vous auriez dû continuer à concevoir.
- certaines bibliothèques s'y attendent, mais pas beaucoup-réflexion, sérialisation, objets simulés tout fonctionne très bien avec les champs publics.
- hériter de cette classe, vous pouvez outrepasser la fonctionnalité par défaut - en d'autres termes, vous pouvez vraiment confondre les appelants par cacher la mise en œuvre, mais la rendre incohérente.
Le dernier des trois, je suis juste de sortir (N/d ou D/C)...
N'utilisez pas de getters setters sauf si vous en avez besoin pour votre livraison actuelle. Ne pensez pas trop à ce qui se passerait dans le futur, si quelque chose à changer son une demande de changement dans la plupart des applications de production, les systèmes.
pensez simple, facile, ajoutez de la complexité au besoin.
Je ne profiterais pas de l'ignorance des propriétaires d'entreprise de savoir-faire technique profond juste parce que je pense que c'est correct ou j'aime l'approche.
j'ai un système Massif écrit sans getters setters seulement avec des modificateurs d'accès et quelques méthodes pour valider n effectuer la logique biz. Si vous avez absolument besoin de l'. Utiliser quoi que ce soit.
j'ai passé pas mal de temps à y réfléchir pour L'affaire Java, et je crois que les vraies raisons sont:
- Code à l'interface, pas la mise en œuvre
- Interfaces spécifiez seulement les méthodes, pas les champs
En d'autres termes, la seule façon vous pouvez spécifier un champ dans une interface est de fournir une méthode pour écrire une nouvelle valeur et une méthode pour lecture de la valeur courante.
Ces méthodes sont l'infâme getter et setter....
nous utilisons getters et setters:
- pour réutilisabilité
- pour effectuer la validation dans les étapes ultérieures de la programmation
les méthodes Getter et setter sont des interfaces publiques permettant d'accéder à des membres de classe privés.
encapsulation mantra
le mantra de l'encapsulation est de rendre les champs privés et les méthodes publiques.
méthodes Getter: nous pouvons accéder à des variables privées.
Setter: Nous pouvons modifier les champs privés.
même si les méthodes getter et setter n'ajoutent pas de nouvelles fonctionnalités, nous pouvons changer d'avis revenir plus tard pour faire de cette méthode
- mieux;
- safer; et
- plus vite.
partout où une valeur peut être utilisée, une méthode qui retourne cette valeur peut être ajoutée. Au lieu de:
int x = 1000 - 500
utiliser
int x = 1000 - class_name.getValue();
en termes simples
supposons que nous ayons besoin de stocker le détails de ce Person
. Ce Person
a les champs name
, age
et sex
. Cela implique la création de méthodes pour name
, age
et sex
. Maintenant, si nous avons besoin de créer une autre personne, il devient nécessaire de créer les méthodes pour name
, age
, sex
encore une fois.
au lieu de faire cela, nous pouvons créer un haricot class(Person)
avec les méthodes getter et setter. Donc demain nous pouvons juste créer objets de ce haricot class(Person class)
chaque fois que nous avons besoin d'ajouter une nouvelle personne (voir la figure). Ainsi nous réutilisons les champs et les méthodes de la classe de haricot, qui est beaucoup mieux.
il peut être utile pour le chargement paresseux. Dire que l'objet en question est stocké dans une base de données, et vous ne voulez pas aller le chercher si vous en avez besoin. Si l'objet est récupéré par un getter, alors l'objet interne peut être nul jusqu'à ce que quelqu'un le demande, alors vous pouvez aller le récupérer au premier appel au getter.
j'ai eu une classe de page de base dans un projet qui m'a été remis qui chargeait des données d'un couple différents appels de service web, mais les données dans ces web les appels de service n'étaient pas toujours utilisés dans toutes les pages destinées aux enfants. Web services, pour tous les avantages, pionnier de nouvelles définitions de "ralentir", de sorte que vous ne voulez pas faire un appel de service web si vous n'avez pas à.
j'ai quitté les champs publics pour getters, et maintenant les getters vérifient le cache, et si ce n'est pas là, appelez le service web. Donc, avec un peu d'habillage, beaucoup d'appels de service web ont été empêchés.
Si la lecture m'évite d'essayer de comprendre, sur chaque page enfant, ce dont j'ai besoin. Si j'en ai besoin, j'appelle de la lecture, et il va le trouver pour moi si je ne l'est pas déjà.
protected YourType _yourName = null;
public YourType YourName{
get
{
if (_yourName == null)
{
_yourName = new YourType();
return _yourName;
}
}
}
un aspect que j'ai manqué dans les réponses jusqu'à présent, la spécification d'accès:
- pour les membres vous n'avez qu'une spécification d'accès pour définir et obtenir
- pour les setters et les getters vous pouvez affiner et définir séparément
dans les langages qui ne prennent pas en charge les" propriétés " (C++, Java) ou qui nécessitent la recompilation des clients lors du Changement des champs en propriétés (c#), l'utilisation des méthodes get/set est plus facile à modifier. Par exemple, l'ajout d'une logique de validation à une méthode setFoo ne nécessitera pas de modifier l'interface publique d'une classe.
dans les langues qui supportent les propriétés "réelles" (Python, Ruby, peut-être Smalltalk?) il n'y a pas de point pour obtenir/définir des méthodes.
EDIT: j'ai répondu à cette question parce qu'il y a un tas de gens qui apprennent la programmation qui pose cette question, et la plupart des réponses sont très techniquement compétentes, mais elles ne sont pas aussi faciles à comprendre si vous êtes un internaute novice. On était tous des débutants, alors j'ai pensé essayer une réponse plus amicale.
les deux principaux sont le polymorphisme et la validation. Même si c'est juste une stupide structure de données.
disons que nous avons cette classe simple:
public class Bottle {
public int amountOfWaterMl;
public int capacityMl;
}
une classe très simple qui tient combien de liquide est en elle, et ce que sa capacité est (en millilitres).
Ce qui se passe quand je fais:
Bottle bot = new Bottle();
bot.amountOfWaterMl = 1500;
bot.capacity = 1000;
Eh bien, vous ne vous attendez pas à ce que cela fonctionne, non? Que vous voulez être une sorte de test de cohérence. Et pire, et si je n'avais jamais spécifié la capacité maximale? Oh, nous avons un problème.
mais il y a un autre problème aussi. Et si les bouteilles étaient juste un type de conteneur? Que faire si nous avions plusieurs conteneurs, tous avec des capacités et des quantités de liquide rempli? Si nous pouvions juste faire une interface, nous pourrions laisser le reste de notre programme accepter cette interface, et les bouteilles, les jerrycans et toutes sortes de choses fonctionneraient de manière interchangeable. Ne serait ce pas mieux? Comme les interfaces exigent des méthodes, c'est également une bonne chose.
nous finirions avec quelque chose comme:
public interface LiquidContainer {
public int getAmountMl();
public void setAmountMl(int amountMl);
public int getCapacityMl();
public void setCapcityMl(int capacityMl);
}
Super! Et maintenant nous avons juste changer la bouteille en ceci:
public class Bottle extends LiquidContainer {
private int capacityMl;
private int amountFilledMl;
public Bottle(int capacityMl, int amountFilledMl) {
this.capacityMl = capacityMl;
this.amountFilledMl = amountFilledMl;
checkNotOverFlow();
}
public int getAmountMl() {
return amountFilledMl;
}
public void setAmountMl(int amountMl) {
this.amountFilled = amountMl;
checkNotOverFlow();
}
public int getCapacityMl() {
return capacityMl;
public void setCapcityMl(int capacityMl) {
this.capacityMl = capacityMl;
checkNotOverFlow();
}
private void checkNotOverFlow() {
if(amountOfWaterMl > capacityMl) {
throw new BottleOverflowException();
}
}
je laisse au lecteur le soin de définir L'exception de flottement en bouteille comme un exercice.
remarquez maintenant à quel point c'est plus robuste. Nous pouvons traiter avec n'importe quel type de conteneur dans notre code maintenant en acceptant LiquidContainer au lieu de bouteille. Et la façon dont ces bouteilles traitent ce genre de choses peut différer. Vous pouvez avoir des bouteilles qui écrivent leur état sur le disque quand il change, ou des bouteilles qui économisent sur les bases de données SQL ou GNU sait quoi d'autre.
et tous ceux-ci peuvent avoir différentes façons de gérer les différents whoopsies. La bouteille ne fait que vérifier et si elle déborde, elle lance une RuntimeException. Mais que peut-être la mauvaise chose à faire. (Il y a une discussion utile à avoir au sujet de la gestion des erreurs, mais je garde cela très simple ici sur le but. Les gens dans les commentaires souligneront probablement les défauts de cette approche simpliste. ;))
et oui, il semble que nous allons d'un très simple idée d'obtenir des réponses beaucoup mieux rapidement.
il y a aussi la troisième chose que tout le monde n'a pas abordée: les Getters et les setters utilisent des appels de méthodes. Cela signifie qu'ils ressemblent à des méthodes normales partout ailleurs. Au lieu d'avoir une syntaxe spécifique bizarre pour les DTOs et autres, vous avez la même chose partout.
un des principes de base de la conception OO: Encapsulation!
il vous donne de nombreux avantages, dont l'un est que vous pouvez changer la mise en œuvre du getter/setter dans les coulisses, mais tout consommateur de cette valeur continuera à travailler aussi longtemps que le type de données reste le même.
du point de vue de la conception de l'orientation de l'objet, les deux solutions peuvent nuire au maintien du code en affaiblissant l'encapsulation des classes. Pour une discussion, vous pouvez regarder dans cet excellent article: http://typicalprogrammer.com/?p=23
vous devez utiliser getters et setters quand:
- vous avez affaire à quelque chose qui est conceptuellement un attribut, mais:
- votre langue n'a pas de propriétés (ou un mécanisme similaire, comme les traces variables de Tcl), ou
- le support de la propriété de votre langue n'est pas suffisant pour ce cas d'utilisation, ou
- les conventions idiomatiques de votre langue (ou parfois de votre cadre) encouragent getters ou setters pour ce cas d'utilisation.
il s'agit donc très rarement d'une question générale; c'est une question spécifique à une langue, avec des réponses différentes pour différentes langues (et différents cas d'utilisation).
du point de vue de la théorie de OO, getters et setters sont inutiles. L'interface de votre classe est ce qu'il fait, pas ce qu'elle est à l'état. (Sinon, vous avez écrit le mauvais cours.) Dans les cas très simples, où ce que fait une classe est juste, par exemple, représenter un point dans des coordonnées rectangulaires,* les attributs font partie de l'interface; getters et setters viennent de cloud that. Mais dans tous les cas sauf les cas très simples, ni les attributs, ni les getters et les setters ne font partie de l'interface.
mettre une autre façon: si vous croyez que les consommateurs de votre classe ne devrait même pas savoir que vous avez un spam
attribut, beaucoup moins être en mesure de le changer délibérément-nilly, puis leur donner une méthode set_spam
est la dernière chose que vous voulez faire.
* même pour cette classe simple, vous ne voudrez peut-être pas nécessairement permettre de définir les valeurs x
et y
. Si c'est vraiment une classe, ne devrait-il pas des méthodes comme translate
, rotate
, etc.? Si ce n'est qu'une classe parce que votre langue n'a pas d'enregistrements/structures/tuples nommés, alors ce n'est pas vraiment une question de OO...
mais personne ne fait jamais de design général OO. Ils font du design, et de la mise en œuvre, dans un langage spécifique. Et dans certaines langues, getters et setters sont loin d'être inutiles.
si votre langue n'a pas de propriétés, alors la seule façon de représenter quelque chose qui est conceptuellement un attribut, mais qui est en fait calculé, ou validé, etc., est à travers getters et setters.
même si votre langue a des propriétés, il peut y avoir des cas où elles sont insuffisantes ou inappropriées. Par exemple, si vous voulez permettre à des sous-classes de contrôler la sémantique d'un attribut, dans des langues sans accès dynamique, une sous-classe ne peut pas substituer une propriété calculée à un attribut.
comme pour le "et si je veux changer mon implémentation plus tard?"question (qui est répétée plusieurs fois dans des formulations différentes à la fois dans la question de L'OP et la réponse acceptée): si c'est vraiment une pure mise en œuvre changement, et que vous avez commencé avec un attribut, vous pouvez la changer en une propriété sans affecter l'interface. À moins, bien sûr, que votre langue ne supporte pas ça. Donc c'est vraiment le même cas encore une fois.
aussi, il est important de suivre les idiomes du langage (ou du cadre) que vous utilisez. Si vous écrivez un beau Code de style Ruby en C#, n'importe quel développeur expérimenté en C# autre que vous aura du mal à le lire, et c'est mauvais. Certaines langues sont plus des cultures plus proches de leurs conventions que d'autres.- et ce n'est peut-être pas une coïncidence que Java et Python, qui sont aux extrémités opposées du spectre pour la façon idiomatique getters sont, arrivent à avoir deux des cultures les plus fortes.
au-delà des lecteurs humains, il y aura des bibliothèques et des outils qui s'attendront à ce que vous suiviez les conventions, et vous rendrez la vie plus difficile si vous ne le faites pas. Brancher des widgets de constructeur D'Interface à n'importe quoi sauf des propriétés ObjC, ou en utilisant certaines bibliothèques de moquerie Java sans getters, ça rend juste ta vie plus difficile. Si les outils sont importants pour vous, ne les combattez pas.
les méthodes Getter et setter sont des méthodes accessor, ce qui signifie qu'elles sont généralement une interface publique pour changer les membres de classe privés. Vous utilisez les méthodes getter et setter pour définir une propriété. Vous accédez aux méthodes getter et setter comme propriétés en dehors de la classe, même si vous les définissez dans la classe comme méthodes. Les biens qui ne font pas partie de la catégorie peuvent avoir un nom différent de celui de la catégorie.
il y a quelques avantages à utiliser getter et les méthodes de setter, comme la possibilité de vous permettre de créer des membres avec des fonctionnalités sophistiquées que vous pouvez accéder comme des propriétés. Ils vous permettent également de créer des propriétés en lecture seule et en écriture seule.
même si les méthodes getter et setter sont utiles, vous devez faire attention à ne pas les abuser car, entre autres choses, elles peuvent rendre la maintenance du code plus difficile dans certaines situations. De plus, ils permettent l'accès à la mise en œuvre de votre classe, comme les membres du public. La programmation orientée objet la pratique décourage l'accès direct aux propriétés d'une classe.
lorsque vous écrivez des classes, vous êtes toujours encouragés à rendre le plus grand nombre possible de vos variables d'instance privées et à ajouter des méthodes getter et setter en conséquence. C'est parce qu'il y a plusieurs fois où vous ne voulez pas laisser les utilisateurs changer certaines variables dans vos classes. Par exemple, si vous avez une méthode statique qui suit le nombre d'instances créées pour une classe spécifique, vous n'avez pas vous voulez qu'un utilisateur modifie ce compteur en utilisant du code. Seule la déclaration du constructeur devrait incrémenter cette variable chaque fois qu'elle est appelée. Dans cette situation, vous pouvez créer une variable d'instance privée et autoriser une méthode getter uniquement pour la variable counter, ce qui signifie que les utilisateurs sont capables de récupérer la valeur courante uniquement en utilisant la méthode getter, et ils ne seront pas en mesure de définir de nouvelles valeurs en utilisant la méthode setter. Créer un getter sans setter est un moyen simple de faire certaines variables dans votre de classe en lecture seule.
Code évolue . private
est idéal pour quand vous avez besoin de la protection des données membre . Finalement toutes les classes devraient être une sorte de" miniprogrammes "qui ont une interface bien définie que vous ne pouvez pas simplement visser avec les internes de .
qui dit, développement logiciel n'est pas une question de mettre en place cette version finale de la classe comme si vous appuyez sur une certaine fonte statue de fer au premier essai. Pendant que vous travaillez avec, le code est plus comme de l'argile. évolue comme vous le développer et d'en apprendre plus sur le domaine du problème à résoudre. Pendant les cours de développement peuvent interagir les uns avec les autres qu'ils devraient (dépendance que vous prévoyez d'exclure), fusionner ensemble, ou séparer. Donc je pense que le débat se résume à des gens qui ne veulent pas écrire religieusement
int getVar() const { return var ; }
donc vous avez:
doSomething( obj->getVar() ) ;
au lieu de
doSomething( obj->var ) ;
Non seulement getVar()
visuellement bruyant, il donne cette illusion que gettingVar()
est en quelque sorte un processus plus complexe qu'il ne l'est vraiment. Comment vous (en tant qu'écrivain de classe) considérez la sainteté de var
est particulièrement déroutant pour un utilisateur de votre classe si elle a un setter passthru -- alors il semble que vous mettez en place ces portes pour "protéger" quelque chose que vous insistez est précieux, (la sainteté de var
) mais même vous concéder var
la protection de " ne vaut pas grand-chose par la capacité pour n'importe qui de venir et set
var
à n'importe quelle valeur ils veulent, sans même que vous regardez ce qu'ils font.
donc je programme comme suit (en supposant une approche de type "agile" -- c.-à-d. quand j'écris le code ne sachant pas exactement ce qu'il fera/n'a pas le temps ou l'expérience pour planifier un ensemble d'interface de style de chute d'eau élaboré):
1) Commencer avec tous les membres publics pour les objets de base avec les données et le comportement. C'est pourquoi dans tout mon code C++ "example" vous me remarquerez en utilisant struct
au lieu de class
partout.
2) Lorsque le comportement interne d'un objet pour un membre de données devient assez complexe, (par exemple, il aime garder un std::list
interne dans une sorte d'ordre), les fonctions de type accessor sont écrites. Parce que je programmais moi-même, Je ne mettais pas toujours membre private
tout de suite, mais quelque part dans l'évolution de la classe, le Membre sera "promu" soit protected
ou private
.
3) Les Classes qui sont entièrement étoffées et ont des règles strictes au sujet de leurs internes (i.e. ils savent exactement ce qu'ils font, et vous n'êtes pas à "baiser" (terme technique) avec ses internes) sont donnés le class
désignation, les membres privés par défaut, et seulement quelques membres choisis sont autorisé à être public
.
je trouve que cette approche me permet d'éviter d'être assis là et d'écrire religieusement getter/setters quand beaucoup de membres de données sont migrés, déplacés, etc. pendant les premières étapes de l'évolution d'une classe.
Il y a une bonne raison d'envisager l'utilisation des accesseurs est la propriété de l'héritage. Voir l'exemple suivant:
public class TestPropertyOverride {
public static class A {
public int i = 0;
public void add() {
i++;
}
public int getI() {
return i;
}
}
public static class B extends A {
public int i = 2;
@Override
public void add() {
i = i + 2;
}
@Override
public int getI() {
return i;
}
}
public static void main(String[] args) {
A a = new B();
System.out.println(a.i);
a.add();
System.out.println(a.i);
System.out.println(a.getI());
}
}
sortie:
0
0
4
une autre utilisation (dans les langages qui supportent les propriétés) est que les setters et les getters peuvent laisser entendre qu'une opération n'est pas triviale. Typiquement, vous voulez éviter de faire quoi que ce soit qui est computationnellement coûteux dans une propriété.
Getters et poseurs sont utilisés pour mettre en œuvre deux des aspects fondamentaux de la Programmation Orientée Objet, qui sont:
- Abstraction
- Encapsulation
supposons que nous ayons une classe D'employés:
package com.highmark.productConfig.types;
public class Employee {
private String firstName;
private String middleName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getMiddleName() {
return middleName;
}
public void setMiddleName(String middleName) {
this.middleName = middleName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getFullName(){
return this.getFirstName() + this.getMiddleName() + this.getLastName();
}
}
ici les détails d'implémentation de Full Name sont cachés à l'utilisateur et ne sont pas accessibles directement à la utilisateur, contrairement à un attribut public.
un avantage relativement moderne des getters/setters est qu'il est plus facile de parcourir le code dans les éditeurs de code étiquetés (indexés). E. g. Si vous voulez voir qui définit un membre, vous pouvez ouvrir la hiérarchie d'appel de l'incubateur.
par contre, si le membre est public, les outils ne permettent pas de filtrer l'accès en lecture/écriture au membre. Vous devez donc passer par tous les usages du membre.
dans un langage orienté objet les méthodes, et leurs modificateurs d'accès, déclarent l'interface pour cet objet. Entre le constructeur et l'accesseur et mutateur méthodes, il est possible pour le développeur de contrôler l'accès à l'état interne d'un objet. Si les variables sont simplement déclarées publiques, il n'y a aucun moyen de réglementer cet accès. Et quand nous utilisons des setters nous pouvons restreindre l'utilisateur pour l'entrée dont nous avons besoin. Signifie que l'alimentation pour cette très variable viendra à travers un bon canal et le canal est prédéfini par nous. Il est donc plus sûr d'utiliser des setters.
de plus, ceci est pour "future-proof" votre classe. En particulier, passer d'un champ à une propriété est un break ABI, donc si vous décidez plus tard que vous avez besoin de plus de logique que juste "set/get the field", alors vous avez besoin de break ABI, ce qui bien sûr crée des problèmes pour tout ce qui est déjà compilé contre votre classe.
je voudrais juste lancer l'idée de l'annotation : @getter et @setter. Avec @getter, vous devriez pouvoir obj = class.champ, mais pas de classe.champ = obj. Avec @setter, vice versa. Avec @getter et @setter vous devriez pouvoir faire les deux. Cela préserverait l'encapsulation et réduirait le temps en n'appelant pas les méthodes triviales à l'exécution.