Évitez les getters et setters, affichant les informations utilisateur


10

Contexte

Je lis le "Clean Code book", et, en parallèle, je travaille sur des objets calisthéniques Kata comme le compte bancaire, et je suis coincé sur cette règle:

La 9ème règle des objets calisthéniques est que nous n'utilisons pas de getter ou de setters.

Cela semble assez amusant et je suis d'accord avec ce principe. De plus, à la page 98-99 de Clean Code, l'auteur explique que les getters / setters brisent l'abstraction, et que nous n'avons pas à demander notre objet, mais nous devons le dire.

Cela est parfaitement logique dans mon esprit et je suis entièrement d'accord avec ce principe. Le problème vient en pratique.

Le contexte

Par exemple, j'ai une application dans laquelle je dois lister certains utilisateurs et afficher les détails de l'utilisateur.

Mon utilisateur est composé de:

-> Name
   --> Firstname --> String
   --> Lastname --> String
-> PostalAddress
   --> Street --> String
   --> PostalCode --> String

Problème

Comment puis-je faire ou que puis-je faire pour éviter les getters lorsque je n'ai besoin que d'afficher une information simple ( et je dois confirmer que je n'ai pas besoin d'opération supplémentaire sur ce champ particulier ) pour afficher la valeur Firstname dans un simple ( prise en charge de sortie aléatoire?

Ce qui me vient à l'esprit

Une solution consiste à faire:

user.getName().getFirstName().getStringValue()

Ce qui est totalement terrible, enfreignant de nombreuses règles des objets calisthéniques et enfreignant la loi Demeter.

Un autre serait quelque chose comme:

String firstName = user.provideFirstnameForOutput();
// That would have called in the user object =>
String firstName = name.provideFirstnameForOutput();
// That would have called in the name object =>
String firstName = firstname.provideFirstnameForOutput();

Mais je ne me sens pas à l'aise avec cette solution, qui ne semble être qu'un "accesseur d'ordre supérieur" comme contourner le getter / setter standard avec une méthode qui ne vise qu'à correspondre à la loi de Demeter ...

Une idée ?

Réponses:


17

L'idée fausse commune à propos de l'idée d'éviter les getters et setters est de les éviter partout, ce qui est impossible lorsque vous arrivez à la surface de votre architecture en interaction avec l'utilisateur.

Vous devez éviter d'utiliser des getters et des setters dans la partie logique métier de votre application, où les objets doivent être protégés à l'aide d'agrégats fournissant le contexte et les méthodes doivent agir comme des commandes.

Pour éviter les getters et setters, vous pouvez concevoir une solution similaire à la programmation réactive , implémentant un système de reporting via des entités observables, mais cela complique extrêmement l'architecture et n'a aucun sens au niveau CRUD de votre application, même si la conception est vraiment bonne pour les interfaces utilisateur.

La décision d'utiliser des getters / setters dépend entièrement de la partie de l'application sur laquelle vous travaillez actuellement. Si votre problème est que l'interface utilisateur utilisant des getters est tout à fait correcte, pour la logique métier, où vous exécuteriez une partie d'un code basé sur une valeur récupérée via un getter, pas tellement (cela crie que la logique aurait dû être réellement encapsulée dans la classe sur laquelle vous appelez le getter).

En outre, la loi de déméter ne consiste pas à compter les points, mais simplement à déchirer une classe fournissant le contexte en utilisant des getters sur la classe pour obtenir ses composants auxquels vous ne devriez pas avoir accès par lui-même.

Si vous pensez que votre interface utilisateur va trop loin dans vos modèles commerciaux, vous pouvez envisager d'introduire des modèles de vue dans votre système en étant responsable de la transformation de parties spécifiques de modèles en représentations visuelles.


D'accord, je pense à cette suggestion, tout comme un mappeur entre mon entité de domaine, à un DTO personnalisé pour ma couche de présentation qui aurait des accesseurs, non?
mfrachet le

@Margin À peu près, oui.
Andy

Tous ces trucs en cascade sonnent vraiment bien et en douceur, merci pour la réponse;)
mfrachet

2

Une direction à penser serait de fournir une fonction membre de formatage de chaîne générique, plutôt que de donner accès aux données brutes. Quelque chose comme ça:

String lastName = user.formatDescription("$(Lastname)");
String fullName = user.formatDescription("$(Lastname), $(Firstname)");
String abbreviated = user.formatDescription("$(FnAbb). $(LnAbb).");

Vous voyez, avec cette approche, vous n'êtes pas limité à simplement fournir les données complètes telles quelles, vous pouvez fournir des moyens de transformer les données de manière pratique et significative. Par exemple, vous devrez peut-être jouer des tours avec la casse des personnages:

String accountName = user.formatDescription("$(firstname).$(lastname)");

Vous pouvez également définir une fois certains formats couramment utilisés, éventuellement complexes, par exemple, par exemple

String fullAddress = user.formatDescription(User.kAddressFormat);

La beauté de cette approche est qu'elle garde les chaînes individuelles internes à la Userclasse, tout en fournissant beaucoup plus de fonctionnalités au code appelant. Cependant, l'inconvénient est que vous devez implémenter le mécanisme de création de modèles dans formatDescription()lequel se trouvent quelques lignes de code.

En tant que tel, cela pourrait être une exagération totale: n'oubliez jamais que les principes de programmation ne sont que des lignes directrices. Et chaque fois que suivre un autre principe viole le principe KISS, il est probablement préférable de le faire simplement. Donc, à moins que vous n'ayez au moins besoin d'un tel membre de mise en forme, je ne prendrais pas la peine de l'implémenter par souci de simplicité, en utilisant l'approche basée sur les accesseurs.


5
Cependant, cela ressemble à une violation de SRP pour moi. Est-ce vraiment la responsabilité d'un Userobjet d'analyser et de compiler / interpréter un langage de template?
Jörg W Mittag

@ JörgWMittag Pas nécessairement. Comme je l'ai dit, le principe KISS a priorité. Et je n'ai dit nulle part que la Userclasse doit implémenter cette fonctionnalité elle-même. Si je n'avais que deux classes qui avaient besoin d'une telle fonctionnalité, vous pourriez parier sur moi en intégrant le mécanisme de remplacement de modèle dans sa propre classe. Ceci est censé être un exemple de la façon dont vous pouvez élever l'abstraction qui Userfournit à un niveau où elle est en fait plus qu'un simple conteneur de données. Et je crois que c'est à cela qu'il faut éviter les accesseurs: faire de la POO au lieu de gérer un tas de structs.
cmaster - réintègre monica le

Vous savez que KISS est totalement subjectif et objectif SRP? KISS ne vous dit rien sur QUOI faire. Et ce qui est "simple" pour vous peut ne pas être "simple" pour moi. Je vois une réelle différence de qualité si je discute avec KISS ou SRP.
oopexpert
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.