septembre
2009
Dans un précédent billet, je faisais état des données membres que l’on veut exposer et je rappelai les avantages du principe d’encapsulation.
Bien entendu, de même qu’il n’est pas question de mettre tous les attributs en visibilité publique, il n’est pas question pour autant de créer des getters/setters pour tous les attributs. (J’aurai même tendance à penser qu’il ne faut les créer que si une classe cliente en a vraiment besoin.)
En poussant un peu plus loin la réflexion, je pense qu’on ne devrait même pas se poser les questions
- getter or not getter ?
- setter or not setter ?
=> Comme beaucoup d’entre vous (j’imagine), j’ai commencé à coder objet de la façon suivante :
- Création de la classe
- Définition d’attributs
- Création de constructeurs avec/sans attributs
- Génération de getters/setters
- Définition de méthodes …
Je ne sais pas si cette approche a influencé ou a été influencée par les outils mais elle s’intègre parfaitement avec eclipse (génération des getters/setters, génération des constructeurs, extraction d’interface, …)
Avec cette approche (bottom-up ?), on part du caché pour aller au visible, on va de l’implémentation à ce qui sera exposé au client. D’où les deux questions évoquées en introduction que l’on peut se poser.
=> Aujourd’hui, j’aurai plutôt tendance à développer en utilisant l’approche diamétralement opposée : partir du visible pour aller au caché, on va de la spécification à l’implémentation.
Je remarque que cette approche (top-down ?):
- évite d’écrire du code inutile
- permet d’écrire du code « plus propre » dans la mesure où on code d’abord les méthodes telles qu’on souhaite les avoir côté client
- convient bien au développement dirigé par les tests (Une classe de test est un client comme un autre)
- nous évite de se poser les questions des mutateurs/accesseurs car à cette étape, on ne sait pas comment sera implémentée la caractéristique (avec ou sans attribut)
- ne m’a pas été enseignée, n’est pas enseignée dans les cursus ??? Et vous, on vous a appris comment pendant vos études ?
=> Notons cependant qu’une fois dans la classe concrète, si on n’a plus à se poser la question de la visibilité publique des attributs (via la présence ou non des getters/setters), il reste la question private or protected ?
Par défaut, j’aurai tendance à préférer protected pour permettre l’extensibilité de mon code.
J’utiliserai private
- si ma classe est finale,
- si la donnée est vraiment interne et ne devrait pas être bidouillé par les classes filles
- si la donnée ne devrait pas être visible par mes classes du même package (parce que malheureusement, en java, les protected ont aussi une visibilité package).
J’utilise rarement la visibilité package (aucun mot clé) pour la raison que si l’attribut n’est pas privé, il est fort probable que des sous classes aient plus d’intérêts à le voir que les autres classes du même package.
Et vous, comment décidez vous du niveau de visibilité ?
Je me demande si je ne vais pas dorénavant utiliser d’avantage de private.
Je reprend du code et avec les warnings d’eclipse, on voit tout de suite les méthodes qui ne sont plus utilisées (code mort).
Je suis d’accord que développer une classe pour qu’elle soit héritée n’est pas une mince affaire.
Cependant, j’ai eu souvent à faire à des corrections/extensions de classes existantes qui m’empêchait de faire ce que je souhaitai parce que des méthodes étaient privées.
Ce n’est probablement pas la bonne approche si les concepteurs de la classe avaient de bonnes raisons de la faire (ce qui devrait être documenté selon moi à l’intérieur du code).
Résultat, parce que j’avais accès au code en lecture, j’ai créé ma classe en copiant/collant/modifiant leur code, ce qui je reconnais, n’est pas très élégant mais bon, d’autres critères étaient à prendre en compte.
salut
C’est un vaste sujet pour lequel je conseille vivement quelques lectures, notamment Effective Java ou Clean code (je suis preneur de toutes autres références d’ailleurs et toujours dans le registre de la pub j’ai bloggué sur ces petits livres sur codesmell).
Vu la littérature sur le sujet, traiter « proprement » du sujet mérite clairement pas mal de texte (et des compétences que je ne pense pas avoir lol).
Maintenant, voici quelques pierres que je pourrai tout de même apporter à l’édifice…
Pour ce qui est de la conception top-down ou bottom-top, je trouve qu’eclipse supporte aussi très bien le « top down » : il peut créer les classes/méthodes/attributs/champs manquants très aisément via des Ctrl 1. C’est limite plus simple que de se rappeler les raccourcis de génération.
D’ailleurs, c’est ce que préconise le Test Driven Development, afin de d’abord se pencher sur l’interface et le service à rendre. Rien de tel qu’écrire un test avec des classes/méthodes non encore existantes pour ensuite demander à eclipse de créer la classe, puis la méthode qu’on voulait. Et en plus si jamais tu te rends compte que le nom n’est pas le plus approprié, changer est aisé vu que tu as des tests
Pour la visibilité des attributs, par défaut, à mon sens, elle doit être private. En effet, comme le dit si bien Joshua Bloch dans Effective Java, concevoir une classe pour qu’elle soit héritée n’est pas une mince affaire. Au delà, même si cette classe doit être héritée pour devenir utilisable, on ne veut certainement pas que tous les champs internes soient accessibles.
Attention, cela ne veut pas dire que tous les champs de ta classe doivent être private, des champs protected peuvent avoir un sens (ou un getter protected suivant le cas). Pour la visibilité package/public, concernant un champ, cela saute moins aux yeux de prime abord.
Pour une méthode par contre, le package private est souvent très utile, notamment entre les classes d’un même package qui doivent bosser ensemble mais pour lesquelles tu ne veux pas que le reste du monde puisse interférer. D’ailleurs, c’est souvent requis pour avoir des classes de test dans un package de même nom que les classes réelles (cf maven pour la mise en pratique aisée ;)) : les classes de test peuvent ainsi directement accéder aux code/fonctions qu’elles doivent tester. J’en parlais justement de là http://www.codesmell.org/blog/2009/09/thoughts-and-questions-on-pragmatic-unit-testing/
j’espère que mes pavés sont digestes et contribuent au débat. Toutes questions bienvenues
++
Salut,
Perso pour les attributs j’opte également pour une visibilité private dans la plupart des cas, quitte à fournir un setter protected pour les classes filles si besoin…
Quand à la visibilité package, elle peut être intéressante avec les classes « liées », comme un Comparator par exemple, où l’on pourrait avoir besoin d’un accès direct à l’implémentation.
a++
Personnellement, on nous as aussi appris ça faux à l’école, mais j’espère que ça va s’améliorer cette année avec les cours de génie logiciel.
Au début j’utilisais du bottom-up bourrin, mais j’essaie maintenant de plus en plus d’utiliser du top-down. Dès que j’ai besoin d’une nouvelle classe, je commence par définir son interface et de déjà appeler les méthodes de l’interface pour voir si mon code est cohérent et seulement ensuite j’implémente cette interface. Dans certains cas, il s’agit également de classes abstraites.
Pour ce qui est de la visibilité des attributs, je suis plus de l’école private, mais peut-être à tort.
> ne m’a pas été enseignée, n’est pas enseignée dans les cursus ??? Et vous, on vous a appris comment pendant vos études ?
+1
Dans l’ensemble, les cours sur l’oriente objet a la fac sont a la limite du 0.
On parle d’héritage…sur 5 niveaux, et d’encapsulation, avec comme exemple, les accesseurs bêtement appliqués a tous les champs prives.
Après, effectivement, dans une appli développé en TDD/BDD/DDD, l’approche top-down est un must
Pour ce qui est de la visibilité, perso, j’ai tendance a tout mettre en private…mais c’est contextuel (pas de clients externes a l’équipe, développement propriétaire et interne)
Après, des qu’on parle framework, j’aurais plutôt tendance a faire comme toi, a savoir mettre en publique les méthodes, fournir des points d’extension, et laisser les membres « caches » en protected