Allen Holub a écrit: « Vous ne devez jamais utiliser fonctions get / set », est-il exact? [dupliquer]

StackOverflow https://stackoverflow.com/questions/996179

Question

    

Cette question a déjà une réponse ici:

         

Allen Holub écrit ce qui suit,

  

Vous ne pouvez pas avoir un programme sans un certain couplage. Quoi qu'il en soit, vous pouvez réduire considérablement le couplage servilement et préceptes OO (orienté objet) (le plus important est que la mise en œuvre d'un objet doit être complètement caché des objets qui l'utilisent). Par exemple, les variables d'instance d'un objet (champs membres qui ne sont pas constantes), doivent toujours être privées. Période. Aucune exception. Déjà. Je suis sérieux. (Vous pouvez parfois utiliser des méthodes efficacement protégées, mais les variables d'instance protégées sont une abomination.)

Ce qui semble raisonnable, mais il va ensuite dire,

  

Vous devez ne jamais utiliser les fonctions get / set pour la même raison: ils sont juste des moyens trop compliqués pour faire un champ public (bien que les fonctions d'accès qui renvoient des objets à part entière plutôt que d'un basic- valeur de type sont raisonnables dans des situations où la classe de l'objet retourné est une abstraction clé dans la conception).

Qui, franchement, tout semble fou pour moi.

Je comprends le principe de dissimulation d'information, mais sans accesseurs et mutateurs on ne pouvait pas utiliser les haricots Java du tout. Je ne sais pas comment vous suivre une conception MVC sans accesseurs dans le modèle, puisque le modèle ne peut pas responsable de rendre la vue.

Cependant, je suis un jeune programmeur et j'apprends plus sur la conception orientée objet quotidien. Peut-être quelqu'un avec plus d'expérience peut peser sur cette question.

articles de Allen Holub pour référence


Questions connexes:

  
Était-ce utile?

La solution

Je n'ai pas de problème avec Holub vous dire que vous devez généralement éviter de modifier le État d'un objet, mais au lieu de recourir à des méthodes intégrées (exécution des comportements) à cette fin. Comme Corletk souligne, il y a la sagesse de penser long et dur sur le plus haut niveau d'abstraction et non-programmation juste inconsidérément avec getters / setters qui permettent simplement vous faire une course de bout autour de l'encapsulation.

Cependant, j'ai beaucoup de mal avec quelqu'un qui vous dit que vous devriez « jamais » utiliser setters ou « jamais » devrait accéder à des types primitifs. En effet, l'effort nécessaire pour maintenir ce niveau de pureté dans tous cas peuvent et finir par causer plus de complexité dans votre code que d'utiliser les propriétés mises en œuvre de façon appropriée. Il vous suffit d'avoir assez de sens pour savoir quand vous Contournant les règles de gain à court terme au détriment de la douleur à long terme.

Holub ne vous fait pas confiance à connaître la différence. Je pense que la différence est de savoir ce que fait de vous un professionnel.

Autres conseils

Lisez cet article attentivement. Holub pousse le point accesseurs sont un mal « par défaut antimodèle », une mauvaise habitude que nous glisser dans la conception d'un système; parce que nous pouvons.

Le processus de pensée doit être le long des lignes; Qu'est-ce que cet objet faire ? Quelles sont ses responsabilités? Quels sont ses comportements? Que faut-il savoir? Penser à long et dur sur ces questions, vous conduit naturellement à la conception des classes qui exposent l'interface de niveau le plus élevé possible.

Une voiture est un bon exemple. Il expose un bien défini, interface normalisée de haut niveau. Je ne me occupe pas setSpeed(60) ... est que MPH ou km / h? J'accélère juste, croisière, décélérer. Je ne dois pas penser aux détails dans setSteeringWheelAngle(getSteeringWheelAngle()+Math.rad(-1.5)), je viens turn(-1.5), et les détails sont pris en charge sous le capot .

Il se résume à « Vous pouvez et devez comprendre ce que chaque classe sera utilisé pour, ce qu'il fait, ce qu'il représente, et d'exposer l'interface plus haut niveau possible, ce qui répond à ces exigences. Accesseurs sont généralement COP- out, lorsque le programmeur est juste paresseux pour faire l'analyse nécessaire pour déterminer exactement ce que chaque classe est et est-pas, et nous allons sur le chemin de « il peut faire quoi que ce soit ». accesseurs sont mal!

Parfois, les besoins réels d'une classe sont à l'avance inconnaissable. C'est cool, juste dérobade et utiliser getter / setter pour l'instant antimodèle, mais quand vous le savez, par expérience, ce que la classe est utilisé pour, vous aurez probablement envie de retour et le nettoyage de l'interface bas niveau sale. Refactoring basé sur « des choses que vous le souhaitez, vous saviez quand vous écrivez la ventouse en premier lieu » est par pour le cours. Vous ne devez pas tout savoir pour faire un bon départ, il est juste que plus vous ne savez, moins réusinage est susceptible d'être nécessaire sur le chemin.

C'est la mentalité qu'il fait la promotion. Accesseurs sont un piège facile à tomber.

Oui, les haricots ont besoin essentiellement des accesseurs, mais pour moi, un haricot est un cas particulier. Les haricots représentent des noms, des choses, des objets identifiables tangibles (voire physiques). Pas beaucoup d'objets ont effectivement des comportements automatiques; La plupart du temps les choses sont manipulées par des forces extérieures, y compris les humains, pour les rendre les choses productives.

daisy.setColor(Color.PINK) est parfaitement logique. Que pouvez vous faire d'autre? Peut-être un esprit Vulcan-meld, pour faire la fleur veulent être rose? Hmmm?

accesseurs ont leur? Mal? endroit. Il est juste, comme toutes les choses OO vraiment bien, nous avons tendance à en abuser, car ils sont sûrs et familiers, sans parler de simple, et donc il pourrait être préférable si noobs ne pas voir ou entendre à leur sujet, au moins jusqu'à ce qu'ils d maîtrisé la chose esprit meld.

Je pense que Allen Holub a essayé de dire, reformulée dans cet article , est le suivant.

  

accesseurs peuvent être utiles pour les variables que vous voulez spécifiquement résumer, mais vous ne devez pas les utiliser pour toutes les variables. En fait, les utiliser pour toutes les variables est l'odeur de code méchant.

Les programmeurs ont trouble et Allen Holub est juste le signaler, est qu'ils utilisent parfois getters / setters pour toutes les variables. Et dans le but d'encapsulation est perdue.

(notez que je viens à ce sous un angle .NET "propriété")

Eh bien, tout simplement - je ne suis pas d'accord avec lui; il fait un grand tapage sur le type de retour de propriétés étant une mauvaise chose, car il peut briser votre code d'appel - mais exactement le même argument s'appliquerait aux arguments de la méthode. Et si vous ne pouvez pas utiliser des méthodes non?

OK, les arguments de méthode peuvent être modifiés que l'élargissement des conversions, mais .... juste pourquoi ... Notez également que dans C # le mot-clé var pourrait atténuer beaucoup de cette douleur perçue.

accesseurs sont pas un détail de mise en œuvre; ils sont l'API publique / contrat. Eh oui, si vous cassez le contracft vous avez des problèmes. Quand est-ce devenu une surprise? De même, il est pas rare que accesseurs d'être non-trivial - dire qu'ils font plus que seulement champs de wrap; ils effectuent des calculs, des contrôles logiques, les notifications, etc. Ils permettent des abstractions à base d'interface d'Etat. Oh, et polymorphisme -. Etc

Re la nature prolixe de accesseurs - en C # (p3 4?). public int Foo {get; private set;} - travail fait

En fin de compte, tout le code est un moyen d'exprimer notre intention au compilateur. Propriétés permettez-moi de le faire de manière type sécurisé, basé sur des contrats, vérifiables, polymorphes extensible, - merci. Pourquoi ai-je besoin de « réparer » ce?

accesseurs sont utilisés comme peu plus qu'un masque pour rendre publique variable privée.

Il est inutile de répéter ce Holub déjà dit, mais le point crucial de c'est que les classes doivent représenter le comportement et non pas seulement l'état.

Je l'ai fait quelques recherches sur Google supplémentaires sur Allen Holub, semble comme il a sa part des opposants là-bas dans la communauté Java.

Le dernier est particulièrement mis en évidence. Le texte de Commentateur est en italique.

  
    

Bien que getIdentity commence par « obtenir » ce n'est pas un accesseur parce qu'il ne se contente pas retourner un champ. Il retourne un objet complexe qui a un comportement raisonnable

  
     

Oh mais attendez ... il est normal d'utiliser accesseurs aussi longtemps que vous retournez des objets au lieu des types primitifs? Maintenant, c'est une autre histoire, mais il est tout aussi stupide pour moi. Parfois, vous avez besoin d'un objet, parfois vous avez besoin d'un type primitif.

     

, je remarque aussi que Allen a radicalement assoupli sa position de sa précédente depuis la colonne sur le même sujet, où le mantra « Ne jamais utiliser accesseurs » n'a pas subi une seule exception. Peut-être qu'il a réalisé après quelques années que accesseurs servent un but après tout ...

     
    

Gardez à l'esprit que je ne l'ai pas fait tout le code de l'interface utilisateur dans la logique métier. J'ai écrit la couche d'interface utilisateur en termes de AWT (Abstract Window Toolkit) ou Swing, qui sont les deux couches d'abstraction.

  
     

bon. Que faire si vous écrivez votre application sur SWT? Comment « abstrait » est vraiment AWT dans ce cas? Il suffit de faire face: ce conseil vous conduit simplement à écrire du code de l'interface utilisateur dans votre logique métier. Quel grand principe. Après tout, il ne fait que comme au moins dix ans que nous avons identifié cette pratique comme l'une des pires décisions de conception que vous pouvez faire dans un projet.

Mon problème est en tant que programmeur novice trébuche parfois sur des articles sur Internet et leur donner plus de crédit alors que je devrais. Peut-être est l'un de ces cas.

Quand les idées comme celles-ci sont présentées à moi, je voudrais jeter un oeil dans les bibliothèques et les cadres que j'utilise et que j'aime utiliser.

Par exemple, bien que certains seront en désaccord, j'aime l'API Java Standard. J'aime aussi le Cadre de printemps. En regardant les cours dans ces bibliothèques, vous remarquerez que très rarement il y a setters et getters qui sont là juste pour exposer une variable interne. Il existe des méthodes appelé getX, mais cela ne signifie pas que ce soit un getter dans le sens conventionnel.

Alors, je pense qu'il a un point, et il est ceci: chaque fois que vous appuyez sur choisissez « Générer getters / setters » dans Eclipse (ou votre IDE de choix), vous devriez prendre un pas en arrière et je me demande ce que vous faites . Est-il vraiment approprié d'exposer cette représentation interne, ou est-ce que je gâcher ma conception à un pas?

Je ne crois pas qu'il dit ne jamais utiliser get / set, mais plutôt en utilisant get / set pour un champ est pas mieux que de faire simplement le domaine public (Nom de la chaîne publique par rapport Nom de la chaîne publique {get; ensemble; }).

Si get / set est utilisé limite la dissimulation d'information de OO qui peut potentiellement vous enfermer dans une mauvaise interface.

Dans l'exemple ci-dessus, le nom est une chaîne; si nous voulons changer plus tard la conception d'ajouter plusieurs noms? L'interface exposée une seule chaîne nous ne pouvons pas ajouter plus sans casser la mise en œuvre existante.

Cependant, si au lieu d'utiliser / setter vous aviez d'abord une méthode telle que Ajouter (nom de chaîne), en interne, vous pouvez traiter le nom singulièrement ou ajouter à une liste ou ce pas, et appeler à l'extérieur de la méthode Add autant de fois que vous pour ajouter d'autres noms.

L'objectif OO est de concevoir avec un niveau d'abstraction; ne pas exposer plus de détails que vous devez absolument.

Il y a des chances si vous avez juste un type primitif enveloppé avec un get / set vous avez cassé ce principe.

Bien sûr, cela est si vous croyez dans les objectifs OO; Je trouve que la plupart ne sont pas, pas vraiment, ils utilisent simplement des objets comme un moyen convienient au code fonctionnel du groupe.

Variables publiques ont un sens lorsque la classe est rien de plus qu'un paquet de données sans réelle cohérence, ou quand il est vraiment, vraiment élémentaire (comme une classe de points). En général, s'il y a une variable dans une classe que vous pensez probablement ne devrait pas être public, cela signifie que la classe a une certaine cohérence, et variables ont une certaine relation qui doit être maintenu, de sorte que toutes les variables devraient être privées.

accesseurs de sens quand ils reflètent une sorte d'idée cohérente. Dans une classe de polygone, par exemple, les coordonnées x et y des sommets donnés ont une signification en dehors de la frontière de classe. Il est sans doute logique d'avoir getters, et il fait probablement logique d'avoir setters. Dans une classe de compte bancaire, le solde est probablement stocké comme une variable privée, et devrait certainement avoir un getter. Si elle a un setter, il doit avoir l'exploitation forestière construite pour préserver auditabilité.

Il y a quelques avantages de accesseurs sur les variables publiques. Ils offrent une certaine séparation de l'interface et la mise en œuvre. Tout simplement parce que un point a une fonction de .getX() ne veut pas dire qu'il doit être un x, puisque .getX() et .setX() peuvent être faits pour fonctionner parfaitement avec les coordonnées radiales. Une autre est qu'il est possible de maintenir invariants de classe, en faisant tout ce qui est nécessaire pour maintenir la classe cohérente au sein du compositeur. Une autre est qu'il est possible d'avoir des fonctionnalités qui déclenche sur un ensemble, comme l'exploitation forestière pour le solde du compte bancaire.

Cependant, pour les classes plus abstraites, les variables membres perdent signification individuelle, et n'a de sens que dans le contexte. Vous n'avez pas besoin de connaître toutes les variables internes d'une classe de flux C de, par exemple. Vous devez savoir comment obtenir des éléments et sortir, et comment effectuer d'autres actions. Si vous comptiez sur la structure interne exacte, vous seriez enliser dans les détails qui pourraient arbitrairement varier entre compilateurs ou versions.

Alors, je dirais que d'utiliser des variables privées presque exclusivement, accesseurs où ils ont un sens réel dans le comportement de l'objet, et non autrement.

Juste parce que accesseurs sont souvent galvaudé ne signifie pas qu'ils ne servent à rien.

Le problème avec les getters / setters est qu'ils essaient d'encapsulation de faux, mais ils cassent réellement en exposant leurs internes. Deuxièmement, ils essaient de faire deux choses distinctes - l'accès à et de contrôler leur état -. Et finissent par faire ni très bien

Il casse l'encapsulation parce que quand vous appelez un get / méthode de jeu que vous devez d'abord connaître le nom (ou avoir une bonne idée) du champ que vous voulez changer, et deuxièmement vous devez connaître son type, par exemple. vous ne pouviez pas appeler

setPositionX("some string");

Si vous connaissez le nom et le type du champ, et le poseur est public, alors tout le monde peut appeler la méthode comme si elle était un champ public de toute façon, il est juste une façon plus complexe de le faire, alors pourquoi ne pas simplifier seulement et en faire un champ public en premier lieu.

En permettant l'accès à son état mais en essayant de le contrôler en même temps, un get / méthode set juste embrouille les choses et finit soit être passe-partout inutile ou trompeuse, en faisant pas vraiment ce qu'il dit qu'il fait par ayant des effets secondaires que l'utilisateur pourrait ne pas attendre. Si la vérification des erreurs est nécessaire, il pourrait être appelé quelque chose comme

public void tryPositionX(int x) throws InvalidParameterException{
    if (x >= 0)
        this.x = x;
    else
        throw new InvalidParameterException("Holy Negatives Batman!");
}

ou si le code supplémentaire est nécessaire, il pourrait être appelé un nom plus précis basé sur ce que toute la méthode fait par exemple.

tryPositionXAndLog(int x) throws InvalidParameterException{
    tryPositionX(x);
    numChanges++;
}

IMHO besoin getters / setters pour faire fonctionner quelque chose est souvent un symptôme d'une mauvaise conception. Utiliser le « dire, ne demandez pas » principe, ou repenser pourquoi un objet doit envoyer ses données d'état en premier lieu. Exposer les méthodes qui modifient le comportement d'un objet au lieu de l'Etat est tout. Les avantages de ce comprennent l'entretien plus facile et plus d'extensibilité.

Vous mentionnez MVC et aussi dire un modèle ne peut pas être responsable de sa vue, pour ce cas, Allen Holub donne un exemple de faire une couche d'abstraction en ayant un "donne-moi un JComponent qui-représente-votre-identité classe" qui dit-il serait « isoler l'identité façon sont représentés du reste du système. » Je ne suis pas assez d'expérience pour dire si cela fonctionne ou non, mais sur la surface, il sonne une idée décente.

getters / setters publics sont mauvais si elles donnent accès aux détails de mise en œuvre. Pourtant, il est raisonnable de lui donner accès aux propriétés de l'objet et getters / setters pour cette utilisation. Par exemple, si voiture a la propriété de couleur, il est acceptable de laisser les clients « observer » à l'aide d'un getter. Si certains clients a besoin de la capacité de recolorer une voiture, la classe peut fournir un setter ( « recolorer » est le nom plus clair cependant). Il est important de ne pas laisser les clients savent comment les propriétés sont stockées dans des objets, comment ils sont maintenus, et ainsi de suite.

Ummmm ... il n'a jamais entendu parler du concept de Encapsulation. Méthodes getter et setter sont mises en place pour contrôler l'accès aux membres d'une classe. En faisant tous les champs visibles publiquement ... tout le monde pouvait écrire ce que les valeurs qu'ils les voulaient invalidait complètement l'objet entier.

Juste au cas où tout le monde est un peu floue sur le concept de Encapsulation, lu sur le sujet ici:

Encapsulation (informatique)

... et s'ils sont vraiment mal, construirait .NET le concept de la propriété dans la langue? (Méthodes getter et setter qui ressemblent un peu plus joli)

EDIT

L'article fait mention Encapsulation:

" accesseurs peuvent être utiles pour les variables que vous voulez spécifiquement résumer, mais vous ne devez pas les utiliser pour toutes les variables. En fait, les utiliser pour toutes les variables est l'odeur de code méchant. "

En utilisant cette méthode conduira à extrêmement difficile de maintenir le code à long terme. Si vous trouvez à mi-chemin à travers un projet qui couvre des années qu'un champ doit être encapsulées, vous allez devoir mettre à jour toutes les références de ce domaine partout dans votre logiciel pour obtenir l'avantage. Ça a l'air beaucoup plus intelligent d'utiliser Encapsulation appropriée à l'avant et en toute sécurité vous le mal de tête plus tard.

Je pense que des accesseurs ne doivent être utilisés pour les variables dont on a besoin pour accéder ou modifier l'extérieur d'une classe. Cela étant dit, je ne crois pas que les variables devraient être rendues publiques sauf si elles sont statiques. En effet, les variables qui sont rendre publiques pas statiques peuvent conduire à leur changé de manière non souhaitable. Disons que vous avez un développeur qui utilise négligemment variables publiques. puis il accède à une variable d'une autre classe et sans le vouloir, le change. Maintenant, il a une erreur dans son logiciel à la suite de cette mésaventure. Voilà pourquoi je crois à la bonne utilisation des accesseurs, mais vous ne les avez pas besoin pour chaque variable privée ou protégée.

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