Question

Quel est l'avantage d'utiliser des getters et des setters - qui ne font que get et set - au lieu de simplement utiliser des champs publics pour ces variables ?

Si les getters et les setters font jamais plus que le simple get/set, je peux comprendre celui-ci très rapidement, mais je ne suis pas sûr à 100 % de comment :

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 nécessite beaucoup moins de code passe-partout.

Était-ce utile?

La solution

Il y a en fait de bonnes raisons à envisager d'utiliser accesseurs plutôt que d'exposer directement les champs d'une classe - au-delà de l'argument de l'encapsulation et de faire des changements futurs plus facile.

Voici les quelques-unes des raisons pour lesquelles je suis au courant:

  • Encapsulation de comportement liés à l'obtention ou définition de la propriété - ce qui permet des fonctionnalités supplémentaires (comme la validation) à ajouter plus facilement par la suite
  • .
  • Hiding la représentation interne de la propriété tout en exposant une propriété en utilisant une autre représentation.
  • L'isolation de votre interface publique du changement -. Permettant l'interface publique reste constante tandis que les changements de mise en œuvre sans affecter les consommateurs existants
  • Contrôle de la durée de vie et gestion de la mémoire sémantique (élimination) de la propriété -. Particulièrement important dans les environnements de mémoire non gérés (comme C ++ ou Objective-C)
  • Fournir un point d'interception de débogage pour lors d'un changement de propriété à l'exécution -. Débogage quand et où une propriété a changé à une valeur particulière peut être assez difficile sans cela dans certaines langues
  • Amélioration de l'interopérabilité avec les bibliothèques qui sont conçus pour fonctionner contre la propriété getter / setters -. Mocking, sérialisation et WPF viennent à l'esprit
  • Permettant de changer la héritières sémantique de la façon dont la propriété se comporte et est exposé en remplaçant les méthodes getter / setter.
  • Permettre le getter / setter à passer autour comme des expressions lambda plutôt que des valeurs.
  • accesseurs peuvent permettre différents niveaux d'accès - par exemple, le get peut être public, mais l'ensemble pourraient être protégés
  • .

Autres conseils

Parce que 2 semaines (mois, années) à partir de maintenant quand vous rendrez compte que votre setter doit faire Plus que juste définir la valeur, vous aussi réaliser que la propriété a été utilisé directement dans 238 autres classes: -)

Un champ public n'est pas pire qu'une paire de getter / setter qui ne fait rien, sauf le retour sur le terrain et lui assigner. Tout d'abord, 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é paires de lecture / définition, ne sont pas. Il y a cette affirmation que vous pouvez changer la mise en œuvre et vos clients ne doivent pas être recompilé. Soi-disant, setters vous permettent d'ajouter des fonctionnalités telles que la validation par la suite et vos clients ne même pas besoin de savoir. Cependant, l'ajout d'une validation à un setter est un changement à ses conditions, une violation du contrat précédent , qui était, tout simplement, « vous pouvez mettre quoi que ce soit ici, et vous pouvez obtenir la même chose plus tard du getter ».

Alors, maintenant que vous avez rompu le contrat, en changeant chaque fichier dans le code de base est quelque chose que vous devriez vouloir faire, éviter. Si vous l'éviter, vous êtes en faisant l'hypothèse que tout le code suppose le contrat pour ces méthodes était différent.

Si cela ne devrait pas avoir été le contrat, l'interface a été permettant aux clients de mettre l'objet dans les états invalides. C'est l'exact opposé de l'encapsulation Si ce champ ne pouvait pas vraiment être réglé sur quoi que ce soit depuis le début, pourquoi ne pas la validation là depuis le début?

Ce même argument vaut pour d'autres avantages supposés de ces intercommunication paires getter / setter: si vous décidez de changer la valeur étant définie, vous rompre le contrat. Si vous remplacez la fonctionnalité par défaut dans une classe dérivée, d'une manière au-delà de quelques modifications inoffensifs (comme l'exploitation forestière ou tout autre comportement non observable), vous rompre le contrat de la classe de base. C'est une violation du principe Liskov substituabilité, qui est considéré comme l'un des principes de OO.

Si une classe a ces getters muets et setters pour tous les domaines, il est une classe qui n'a pas invariants que ce soit, pas de contrat . Est-ce vraiment la conception orientée objet? Si toute la classe a est les accesseurs, il est juste un support de données muet et données muets détenteurs devraient ressembler les détenteurs de données muets:

class Foo {
public:
    int DaysLeft;
    int ContestantNumber;
};

Ajout pass-through getter / paires de définition pour une telle classe ajoute aucune valeur. D'autres classes devraient fournir des opérations significatives, non seulement les opérations que les champs fournissent déjà. Voilà comment vous pouvez définir et maintenir des invariants utiles.

  

Client : "Que puis-je faire avec un objet de cette classe"
   Designer : "Vous pouvez lire et écrire plusieurs variables"
   Client : "Oh ... cool, je suppose"

Il y a des raisons d'utiliser des accesseurs, mais si ces raisons n'existent pas, faisant des paires getter / setter au nom des faux dieux d'encapsulation est pas une bonne chose. Des raisons valables pour faire getters ou setters comprennent 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 la valeur doit être lisible par les clients, mais pas accessible en écriture (par exemple, la lecture de la taille d'un dictionnaire), donc un getter simple est un bon choix. Mais ces raisons devraient être là quand vous faites le choix, et non pas seulement comme une chose possible, vous voudrez peut-être plus tard. Ceci est une instance de YAGNI ( yagni ).

Beaucoup de gens parlent des avantages de accesseurs, mais je veux jouer l'avocat du diable. En ce moment je suis le débogage d'un programme très important où les programmeurs ont décidé de faire tout accesseurs. Cela peut sembler agréable, mais son cauchemar ingénierie inverse.

Dites que vous êtes à la recherche à travers des centaines de lignes de code et vous tombez sur ceci:

person.name = "Joe";

Il est un morceau magnifiquement simplement de code jusqu'à ce que vous réalisez que son setter. Maintenant, vous suivez cette setter et trouvez qu'il fixe également person.firstName, person.lastName, person.isHuman, person.hasReallyCommonFirstName et appelle person.update (), qui envoie une requête vers la base de données, etc. Oh, c'est où votre fuite de mémoire se produisait.

Comprendre un morceau locale de code au premier coup d'œil est une propriété importante de la bonne lisibilité que des accesseurs ont tendance à se briser. Voilà pourquoi j'essaie de les éviter quand je peux, et minimiser ce qu'ils font quand je les utilise.

Il y a plusieurs raisons.Mon préféré est lorsque vous devez modifier le comportement ou réguler ce que vous pouvez définir sur une variable.Par exemple, disons que vous aviez une méthode setSpeed(int speed).Mais vous souhaitez que vous ne puissiez définir qu'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;
  }
}

Et si PARTOUT dans votre code vous utilisiez le champ public et que vous réalisiez que vous avez besoin de l'exigence ci-dessus ?Amusez-vous à traquer chaque utilisation du domaine public au lieu de simplement modifier votre passeur.

Mes 2 centimes :)

Dans un monde orienté objet pur accesseurs est un anti-modèle terribles . Lisez cet article: Getters / Setters. Mal. Période. En un mot, ils encouragent les programmeurs à penser à des objets comme des 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 structures de données, mais seulement des objets qui exposent le comportement (pas les attributs / propriétés!)

Vous trouverez peut-être plus à leur sujet dans la section 3.5 objets élégants (mon livre sur la programmation orientée objet).

L'un des avantages de accesseurs et mutateurs est que vous pouvez effectuer la validation.

Par exemple, si foo était publique, je pourrais facilement mettre à null puis quelqu'un d'autre pourrait essayer d'appeler une méthode sur l'objet. Mais ce n'est pas plus là! Avec une méthode setFoo, je pouvais faire en sorte que foo n'a jamais été mis à null.

accesseurs et mutateurs permettent également d'encapsulation - si vous n'êtes pas censé voir la valeur une fois son jeu (peut-être il est défini dans le constructeur, puis utilisé par des méthodes, mais jamais supposé être changé), il ne sera jamais été vu par n'importe qui. Mais si vous pouvez permettre à d'autres classes pour voir ou changer, vous pouvez fournir l'accesseur appropriée et / ou mutator.

Cela dépend de votre langue. Vous avez balisé cela plutôt que de « Java » « orientée objet- », donc je voudrais souligner que la réponse de ChssPly76 dépend de la langue. En Python, par exemple, il n'y a aucune raison d'utiliser des accesseurs. 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 des 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 l'on veut coder un véritable objet programme orienté, alors nous devons STOP accesseurs L'utilisation excessive , car nous dépendons parfois beaucoup sur eux quand est pas vraiment nécessaire et qui fait presque la même chose que si l'on met les variables publiques.

Merci, qui a vraiment clarifié ma pensée. Maintenant, voici (presque) 10 (presque) de bonnes raisons de ne pas utiliser accesseurs:

  1. 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 avez directement accédé.
  2. Toute validation que vous effectuez là ne peut être que le contexte libre, ce qui est rarement la validation dans la pratique.
  3. Vous pouvez modifier la valeur étant set -. C'est un cauchemar absolu lorsque l'appelant vous transmet une valeur qu'ils [l'horreur de choc] veulent que vous stocker AS IS
  4. Vous pouvez cacher la représentation interne - fantastique, vous vous assurez que toutes ces opérations sont symétriques droit
  5. Vous avez isolée votre interface publique de changements sous les draps - si vous deviez concevoir une interface et ne savaient pas si un accès direct à quelque chose était OK, alors vous devriez avoir gardé la conception
  6. .
  7. Certaines bibliothèques attendent, mais pas beaucoup - la réflexion, la sérialisation, les objets fantaisie fonctionnent tous très bien avec des champs publics
  8. .
  9. Héritant cette classe, vous pouvez remplacer la fonctionnalité par défaut -. Autrement dit, vous pouvez vraiment confondre les appelants en se cachant non seulement la mise en œuvre, mais le rendant incompatible

Les trois derniers, je suis juste de quitter (N / A ou D / C) ...

Je sais qu'il est un peu tard, mais je pense qu'il ya des gens qui sont intéressés à la performance.

Je l'ai fait un petit test de performance. J'ai écrit une classe « NumberHolder » qui, bien, détient un nombre entier. Vous pouvez lire cet entier en utilisant la méthode getter anInstance.getNumber() ou en accédant directement le numéro à l'aide anInstance.number. Mon programm lit le numéro 1000000000 fois, par les deux sens. Ce processus est répété cinq fois et le temps est imprimé. J'ai 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

(Time 1 est la voie directe, Temps 2 est le getter)

Vous voyez, le getter est (presque) toujours un peu plus rapide. Alors j'ai essayé avec différents nombres de cycles. Au lieu de 1 million, je 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 les 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

En outre avec différentes quantités de cycles, le getter est un peu plus rapide que la façon régulière. J'espère que cela vous a aidé.

Ne pas utiliser setters getters moins nécessaire pour votre livraison en cours à savoir Ne pensez pas trop à ce qui se passerait à l'avenir, si quelque chose à modifier sa demande de changement dans la plupart des applications de production, des systèmes.

Pensez simple, facile, ajouter de la complexité en cas de besoin.

Je ne pas profiter de l'ignorance des propriétaires d'entreprises de savoir-faire technique en profondeur la façon juste parce que je pense qu'il est correct ou j'aime l'approche.

J'ai écrit sans système massif setters getters uniquement avec des modificateurs d'accès et des méthodes pour valider n exécuter la logique biz. Si vous absolument besoin du. Utilisez quoi que ce soit.

J'ai passé tout en pensant à ce plus le cas Java, et je crois que les vraies raisons sont:

  1. Code de l'interface, et non la mise en œuvre
  2. Interfaces préciser que les méthodes, pas des champs

En d'autres termes, la seule façon que vous pouvez spécifier un champ dans une interface est en fournissant une méthode pour écrire une nouvelle valeur et une méthode de lecture de la valeur actuelle.

Ces méthodes sont le getter infâme et régleurs ....

Nous utilisons accesseurs:

  • pour réutilisabilité
  • pour effectuer la validation dans les étapes ultérieures de la programmation

méthodes getter et setter sont des interfaces publiques pour accéder aux membres de la classe privée.


mantra Encapsulation

Le mantra d'encapsulation est de rendre les champs privés et les méthodes publiques.

  

Méthodes Getter:. Nous pouvons avoir accès à des variables privées

     

Méthodes Setter:. Nous pouvons modifier les champs privés

Même si les méthodes getter et setter ne pas ajouter de nouvelles fonctionnalités, nous pouvons changer notre esprit revenir plus tard pour faire cette méthode

  • mieux;
  • plus sûr; et
  • plus rapide.

Partout une valeur peut être utilisée, une méthode qui renvoie cette valeur peut être ajoutée. Au lieu de:

int x = 1000 - 500

utilisation

int x = 1000 - class_name.getValue();

En termes simples

Représentation de "personne" classe

Supposons que nous devons stocker les détails de cette Person. Ce Person a les champs name, age et sex. Faire 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 tout recommencer.

Au lieu de faire cela, nous pouvons créer un class(Person) de haricot avec getter et setter. Donc, demain, nous pouvons tout simplement créer des objets de ce class(Person class) Bean chaque fois que nous devons ajouter une nouvelle personne (voir la figure). Ainsi, nous réutilisons les champs et les méthodes de la classe de haricot, ce qui est beaucoup mieux.

Il peut être utile pour chargement paresseux. Dites l'objet en question est stocké dans une base de données, et vous ne voulez pas aller le chercher à moins que vous en avez besoin. Si l'objet est récupéré par un getter, l'objet interne peut être nul jusqu'à ce que quelqu'un le demande, alors vous pouvez aller chercher sur le premier appel au getter.

J'ai eu une classe de page de base dans un projet qui m'a été remis à ce chargeais des données à partir d'un autre couple appels de service Web, mais les données contenues dans ces appels de service Web n'a pas toujours été utilisé dans toutes les pages de l'enfant. services Web, pour tous les avantages, pionnier de nouvelles définitions de « lente », de sorte que vous ne voulez pas faire un appel de service Web si vous n'avez pas.

je me suis déplacé des champs publics à getter, et maintenant les getters vérifier le cache, et si ce n'est pas appeler là le service Web. Donc, avec un peu d'emballage, beaucoup d'appels de service Web ont été empêchés.

Ainsi, le getter me sauve d'essayer de comprendre, sur chaque page enfant, ce que je aurai besoin. Si je en ai besoin, je l'appelle le getter, et il va le trouver pour moi si je ne l'ai pas déjà.

    protected YourType _yourName = null;
    public YourType YourName{
      get
      {
        if (_yourName == null)
        {
          _yourName = new YourType();
          return _yourName;
        }
      }
    }

L'un des aspects que j'ai raté dans les réponses à ce jour, la spécification d'accès:

  • pour les membres que vous avez seulement une spécification d'accès pour les obtenir et réglage
  • pour setters et getters vous pouvez affiner et définir séparément

Dans les langues qui ne prennent pas en charge « Propriétés » (C ++, Java) ou nécessitent recompilation des clients lors de la modification des champs aux propriétés (C #), en utilisant les méthodes get / set est plus facile à modifier. Par exemple, l'ajout d'une logique de validation à une méthode setFoo ne nécessite pas de changer l'interface publique d'une classe.

Dans les langues qui soutiennent les propriétés "réelles" (Python, Ruby, peut-être Smalltalk?) Il n'y a pas de point d'obtenir / méthodes définies.

EDIT: Je répondu à cette question parce qu'il ya un tas de gens programmation d'apprentissage en demandant cela, et la plupart des réponses sont très compétents sur le plan technique, mais ils ne sont pas aussi faciles à comprendre si vous êtes un débutant. Nous étions tous les débutants, donc je pensais que je vais essayer ma main à une réponse plus amicale débutant.

Les deux principaux sont le polymorphisme et la validation. Même si elle est juste une structure de données stupide.

Disons que nous avons cette classe simple:

public class Bottle {
  public int amountOfWaterMl;
  public int capacityMl;
}

Une classe très simple qui tient la quantité de liquide est, et ce que sa capacité est (en millilitres).

Qu'est-ce qui se passe quand je fais:

Bottle bot = new Bottle();
bot.amountOfWaterMl = 1500;
bot.capacityMl = 1000;

Eh bien, vous ne penseriez pas que pour travailler, non? Vous voulez qu'il y ait une sorte de vérification de la santé mentale. Et pire, si je jamais précisé la capacité maximale? Oh, nous avons un problème.

Mais là aussi un autre problème. Que faire si les bouteilles étaient un seul type de conteneur? Et si nous avions plusieurs conteneurs, tous avec des capacités et des quantités de liquide remplies? Si nous pouvions faire une interface, nous pourrions laisser le reste de notre programme accepte cette interface, et des bouteilles, des jerrycans et toutes sortes de choses devraient simplement travailler de façon interchangeable. Ne serait-ce mieux? Étant donné que les méthodes de demande d'interfaces, c'est aussi une bonne chose.

Nous finirions avec quelque chose comme:

public interface LiquidContainer {
  public int getAmountMl();
  public void setAmountMl(int amountMl);
  public int getCapacityMl();
}

Great! Et maintenant, nous changeons simplement bouteille à 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;
  }

  private void checkNotOverFlow() {
    if(amountOfWaterMl > capacityMl) {
      throw new BottleOverflowException();
    }
}

Je vais laisser la définition du BottleOverflowException comme un exercice au lecteur.

Maintenant, remarquez combien plus robuste c'est. Nous pouvons faire face à tout type de conteneur dans notre code maintenant en acceptant LiquidContainer au lieu de la bouteille. Et comment ces bouteilles traitent ce genre de choses peuvent tous différer. Vous pouvez avoir des bouteilles qui écrivent leur état sur le disque quand il change, ou des bouteilles qui permettent d'économiser sur les bases de données SQL ou GNU sait quoi d'autre.

Et tout cela peut avoir différentes façons de gérer divers whoopsies. La bouteille vérifie juste et si ça déborde, il jette un RuntimeException. Mais cela pourrait être la mauvaise chose à faire. (Il y a une discussion utile à eu sur la gestion des erreurs, mais je le garde très simple ici sur le but Les gens dans les commentaires pointeront probablement les défauts de cette approche simpliste..))

Et oui, il semble que nous allons d'une idée très simple à obtenir des réponses beaucoup mieux rapidement.

S'il vous plaît noter également que vous ne pouvez pas modifier la capacité d'une bouteille. Il est maintenant gravée dans le marbre. Vous pouvez le faire avec un entier en le déclarant final. Mais si cela était une liste, vous pouvez vider, ajouter de nouvelles choses à lui, et ainsi de suite. Vous ne pouvez pas limiter l'accès à toucher les entrailles.

Il y a aussi la troisième chose que tout le monde a répondu: accesseurs utilisent les appels de méthode. Cela veut dire qu'ils ressemblent à des méthodes normales le fait partout ailleurs. Au lieu d'avoir une syntaxe spécifique bizarre pour DTO et des choses, vous avez la même chose partout.

L'un des principes de base de la conception OO: Encapsulation

Il vous donne de nombreux avantages, dont un être 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.

Vous devez utiliser accesseurs lorsque:

  • Vous avez affaire à quelque chose qui est un attribut conceptuel, mais:
    • Votre langue ne possède pas de propriétés (ou un mécanisme similaire, comme des traces variables de Tcl) ou
    • soutien de la propriété de votre langue ne suffit pas pour ce cas d'utilisation, ou
    • de votre langue (ou parfois de votre cadre) idiomatiques conventions encouragent getters ou setters pour ce cas d'utilisation.

Donc ce qui est très rarement une question générale OO; il est une question spécifique à la langue, avec des réponses différentes pour différentes langues (et les différents cas d'utilisation).


D'un point de vue de la théorie OO, accesseurs sont inutiles. L'interface de votre classe est ce qu'il fait, pas ce que son état est. (Sinon, vous avez écrit la mauvaise classe.) Dans les cas très simples, où ce qu'est une classe n'est juste, par exemple, représentent un point de coordonnées rectangulaires, * les attributs font partie de l'interface; accesseurs nuage juste que. Mais dans quoi que ce soit, mais des cas très simples, ni les attributs ni accesseurs font partie de l'interface.

Autrement dit: Si vous pensez que les consommateurs de votre classe ne devraient pas savoir même que vous avez un attribut spam, beaucoup moins en mesure de changer bon gré mal gré, puis leur donner une méthode de set_spam est la dernière chose que vous voulez faire.

* Même pour cette classe simple, vous voudrez peut-être pas nécessairement pour permettre le réglage des valeurs de x et y. Si cela est vraiment une classe, il ne devrait pas avoir des méthodes telles que translate, rotate, etc.? Si c'est seulement une classe parce que votre langue ne pas enregistre / struct / tuples nommés, alors ce n'est pas vraiment une question de OO ...


Mais personne ne jamais faire la conception générale OO. Ils font la conception et la mise en œuvre, dans une langue spécifique. Et dans certaines langues, accesseurs sont loin d'être inutile.

Si votre langue ne possède pas de propriétés, la seule façon de représenter quelque chose qui est un attribut conceptuel, mais est en fait calculé ou validé, etc., est par accesseurs.

Même si votre langue n'ont des propriétés, il peut y avoir des cas où ils sont insuffisants ou inappropriés. Par exemple, si vous souhaitez autoriser les sous-classes de contrôler la sémantique d'un attribut, dans les langues sans accès dynamique, une sous-classe ne peut pas remplacer une propriété calculée pour un attribut.

Quant à la « si je veux changer ma mise en œuvre plus tard? » question (qui se répète plusieurs fois dans des termes différents dans les deux la question de l'OP et la réponse acceptée): S'il est vraiment un pur changement de mise en œuvre, et vous avez commencé avec un attribut, vous pouvez le remplacer par une propriété sans affecter l'interface. À moins, bien sûr, votre langue ne supporte pas. Donc, c'est vraiment la même affaire à nouveau.

En outre, il est important de suivre les idiomes de la langue (ou cadre) que vous utilisez. Si vous écrivez beau code de type Ruby en C #, tout développeur C # expérimenté autre que vous va avoir du mal à lire, et qui est mauvais. Certaines langues ont plus fortes cultures autour de leurs conventions que autres. et il ne peut pas être une coïncidence que Java et Python, qui sont sur les extrémités opposées du spectre pour savoir comment idiomatiques getters sont, arrive d'avoir deux des cultures les plus fortes.

Au-delà des lecteurs humains, il y aura des bibliothèques et les outils que vous attendez de suivre les conventions, et de rendre votre vie plus difficile si vous ne le faites pas. Interface Builder widgets crochetage à quoi que ce soit, mais les propriétés ObjC, ou l'utilisation de certaines Java se moquant des bibliothèques sans getter, est tout simplement de rendre votre vie plus difficile. Si les outils sont importants pour vous, ne les combattez pas.

Du point de vue de la conception de l'orientation objet les deux alternatives peuvent être dommageables pour le maintien du code en affaiblissant l'encapsulation des classes. Pour une discussion, vous pouvez regarder dans cet excellent article: http://typicalprogrammer.com/?p=23

méthodes getter et setter sont des méthodes accesseurs, ce qui signifie qu'ils sont généralement une interface publique pour changer les membres de la classe privée. Vous utilisez des méthodes getter et setter pour définir une propriété. Vous accédez à des méthodes de lecture et de définition en tant que propriétés en dehors de la classe, même si vous les définissez dans la classe en tant que méthodes. Ces propriétés en dehors de la classe peuvent avoir un nom différent du nom de la propriété dans la classe.

Il y a quelques avantages à utiliser des méthodes getter et setter, tels que la capacité de vous permettre de créer des membres avec des fonctionnalités sophistiquées que vous pouvez accéder à des propriétés similaires. Ils permettent également de créer en lecture seule et les propriétés en écriture seule.

Même si les méthodes getter et setter sont utiles, vous devriez faire attention à ne pas en abuser parce que, entre autres, ils peuvent faire la maintenance du code plus difficile dans certaines situations. , Ils offrent également un accès à votre mise en œuvre de classe, comme les membres du public. la pratique de la POO décourage l'accès direct aux propriétés dans une classe.

Lorsque vous écrivez des classes, vous êtes toujours encouragés à faire autant que possible privé et ajouter vos variables d'instance méthodes de lecture et de définition en conséquence. En effet, il y a plusieurs moments où vous voudrez peut-être de ne pas permettre aux utilisateurs de changer certaines variables au sein de vos classes. Par exemple, si vous avez une méthode statique privée qui suit le nombre d'instances créées pour une classe spécifique, vous ne voulez pas un utilisateur de modifier ce compteur en utilisant le code. Seule la déclaration du constructeur devrait augmenter cette variable chaque fois qu'il est appelé. Dans cette situation, vous pouvez créer une variable d'instance privée et permettre une méthode de lecture uniquement pour la variable compteur, ce qui signifie que les utilisateurs sont en mesure de récupérer la valeur actuelle 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 de définition. Création d'un getter sans setter est un moyen simple de faire certaines variables dans votre classe en lecture seule.

code évolue . private est idéal lorsque vous avez besoin de protection des membres de données . Finalement, toutes les classes devraient être une sorte de « miniprograms » qui ont une interface bien définie que vous ne pouvez pas vis juste avec les entrailles de .

Cela dit, développement de logiciels n'est pas sur la configuration vers le bas que la version finale de la classe comme si vous appuyez sur une statue en fonte sur le premier essai. Pendant que vous travaillez avec elle, le code est plus comme l'argile. Il évolue que vous développez et en apprendre davantage sur le domaine du problème que vous résolvez. Pendant les cours de développement peuvent interagir les uns avec les autres qu'ils ne le devraient (dépendance vous envisagez de factoriser), fusionner ou diviser. Je pense donc que le débat se résume à des gens de ne pas vouloir écrire religieusement

int getVar() const { return var ; }

Vous avez donc:

doSomething( obj->getVar() ) ;

Au lieu de

doSomething( obj->var ) ;

Non seulement il donne est getVar() visuellement bruyant, cette illusion que gettingVar() est en quelque sorte un processus plus complexe qu'elle ne l'est vraiment. Comment vous (comme l'écrivain de classe) considèrent le caractère sacré de var est particulièrement déroutante pour un utilisateur de votre classe si elle a un poseur de passthru - il semble que vous mettre en place ces portes pour « protéger » quelque chose que vous insistez est précieux , (le caractère sacré de var), mais encore même vous concèdent la protection de var ne vaut pas beaucoup par la possibilité pour quiconque de venir juste et set var à toute valeur qu'ils veulent, sans même jeter un oeil à ce qu'ils font.

Je programme comme suit (en supposant une approche de type « agile » - à savoir quand j'écrire du code ne sachant pas exactement ce qu'il va faire / n'ont pas le temps ou d'expérience pour planifier un complexe interface de style cascade jeu):

1) Commencez par tous les membres du public pour les objets de base avec des données et des comportements. Voilà pourquoi, dans tout mon C ++ code « exemple » vous me remarquerez, en utilisant struct au lieu de class partout.

2) Lorsque le comportement interne d'un membre de données d'un objet devient assez complexe, (par exemple, il aime garder un std::list interne dans une sorte d'ordre), les fonctions de type accesseur sont écrits. Parce que je suis la programmation par moi-même, je ne mets pas toujours le private membre tout de suite, mais quelque part l'évolution de la classe du membre sera « promu » à l'une ou protected private.

3) Les classes qui sont pleinement étoffés et ont des règles strictes au sujet de leurs internes (par exemple ils savent exactement ce qu'ils font, et vous n'êtes pas à « fuck » (terme technique) avec ses internes ) sont donnés la désignation class, par défaut les membres privés, et seulement quelques membres de sélection sont autorisés à être public.

Je trouve cette approche me permet d'éviter de rester assis là et écrire religieusement getter / setters quand un grand nombre de membres de données se migrait, détournaient les, etc. au cours des premières étapes de l'évolution d'une classe.

Il y a une bonne raison d'envisager l'utilisation accesseurs est il n'y a pas 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

accesseurs et setters sont utilisés pour mettre en œuvre deux des aspects fondamentaux de la programmation orientée objet qui sont:

  1. Abstraction
  2. 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();
    }
 }

Voici les détails de mise en œuvre du nom complet est caché de l'utilisateur et ne sont pas accessibles directement à l'utilisateur, contrairement à un attribut public.

Une autre utilisation (dans les langues qui prennent en charge les propriétés) est que setters et getters peuvent impliquent qu'une opération est non négligeable. En règle générale, vous voulez éviter tout ce qui est cher dans une informatiquement propriété.

L'un des avantages relativement moderne de getters / setters est qu'il rend plus facile de naviguer dans le code tagués (indexés) éditeurs de code. Par exemple. Si vous voulez voir qui fixe un membre, vous pouvez ouvrir la hiérarchie d'appel du compositeur.

D'autre part, si le membre est public, les outils ne permettent pas de filtrer l'accès en lecture / écriture au membre. Donc, il faut crapahuter que toutes les utilisations 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 des procédés de mutation, il est possible pour le promoteur pour contrôler l'accès à l'état interne d'un objet. Si les variables sont simplement déclarés alors public, il n'y a aucun moyen de réglementer l'accès. Et quand nous utilisons setters nous pouvons restreindre l'utilisateur pour l'entrée nous avons besoin. L'alimentation moyenne pour cette variable très viendra à travers un canal approprié et le canal est par nous prédéfini. Il est donc plus sûr d'utiliser setters.

De plus, c'est à « l'épreuve du futur » de votre classe. En particulier, le passage d'un champ à une propriété est une rupture ABI, donc si vous décidez plus tard que vous avez besoin de plus logique que de « définir / obtenir le champ », alors vous devez briser ABI, ce qui bien sûr crée des problèmes pour quoi que ce soit d'autre déjà compilé avec votre classe.

Je voudrais juste jeter l'idée d'annotation: @getter et @setter. Avec @getter, vous devriez être en mesure de obj = class.field mais pas class.field = obj. Avec @setter, vice-versa. Avec @getter et @setter vous devriez être en mesure de faire les deux. Cela permettrait de préserver l'encapsulation et réduire le temps de ne pas appeler des méthodes triviales lors de l'exécution.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top