Dois-je créer des interfaces pour les objets de transfert de données?
19
Est-ce une bonne ou une mauvaise idée de créer une interface pour les objets de transfert de données? En supposant que l'objet est généralement modifiable.
Bien que mon exemple soit en Java, il devrait être applicable à tout autre langage ayant des concepts similaires.
La réponse générale est non , car vous ne devez jamais ajouter de code sans avoir une raison spécifique et concrète, et il n'y a pas de raison générale pour une telle interface.
Cela étant dit, il peut parfois y avoir une bonne raison. Mais dans tous les cas que j'ai vus, ces interfaces étaient partielles, ne couvrant qu'une ou quelques propriétés partagées par plusieurs classes que je voulais utiliser polymporphiquement sans leur donner une superclasse commune. Les candidats typiques sont une Idpropriété à utiliser dans une sorte de registre ou une Namepropriété à afficher pour l'utilisateur. Mais cela peut être utile dans tous les cas où vous voulez que du code gère tout ce qui a un X - créez simplement une XSourceinterface qui contient les méthodes getX(et, seulement si nécessaire setX).
Mais une interface distincte pour chaque classe de modèle, contenant toutes les propriétés? Je ne peux pas imaginer une bonne raison de faire ça. Une mauvaise raison serait un cadre mal conçu qui l'exige; Les EJB d'entité ont fait exactement cela, si je me souviens bien. Heureusement, ils étaient si mauvais qu'ils n'ont jamais gagné beaucoup de traction et sont obsolètes depuis EJB 3.0
Sidenote: veuillez éviter d'utiliser le terme "objet de valeur" pour décrire les beans Java avec seulement des getters et des setters triviaux - cela entre en conflit avec la définition plus courante de l' objet de valeur comme quelque chose sans identité qui est généralement immuable. Un meilleur terme serait DTO ou classe de modèle - bien que dans ce dernier cas, notez que les modèles de domaine anémique sont considérés comme un contre- modèle .
"les modèles de domaine anémique sont considérés comme un contre-modèle" - par Martin Fowler qui, dans PEAA, admet qu'il connaît des gens qui ont travaillé de cette façon pendant des décennies "avec beaucoup de succès". Ainsi, je suggère, moins un anti-modèle et plus un non-comment-Fowler-aime-travailler. Néanmoins, bonne réponse, +1.
pdr
4
@pdr: Fowler a peut-être inventé le terme, mais il n'est en aucun cas le seul à les considérer comme un contre-modèle. Je ne pense pas que quiconque a réellement compris OO pense que c'est une bonne idée de garder la logique spécifique au domaine en dehors du modèle de domaine.
Michael Borgwardt
Merci pour la correction du terme, DTO était le mot que je cherchais hier soir mais je ne me souvenais pas de ma vie. En changeant le nom, les choses étaient plus judicieuses en termes de design.
Archimedes Trajano
@pdr Je pense que la meilleure façon de le dire est que c'est un contre-modèle dans le contexte de la programmation OO. Il existe de nombreux autres paradigmes où c'est parfaitement bien, et vous pourriez même réussir à travailler de cette façon dans un langage OO (il ne serait tout simplement pas particulièrement orienté objet).
Daniel B
3
@MichaelBorgwardt: Je suis d'accord, il n'est pas seul là-dedans. Mais les gens non plus ne sont pas d'accord. Si vous aviez dit que "les modèles de domaine anémique sont considérés par certains comme un anti-modèle", je n'aurais rien dit. Franchement, je pense que votre réponse serait mieux sans le dernier paragraphe de toute façon. Le premier semestre aurait fait un meilleur commentaire; la seconde moitié n'apporte rien à cette question.
pdr
2
La création d'une interface est correcte, mais PAS la façon dont fonctionne votre exemple. Vous devez supprimer le setter de l'interface, et ça ira:
interfaceValueObject{String getName();};
Cela permet de nombreuses implémentations différentes de celui-ci, comme le nom peut être récupéré de la base de données ... Setter doit être dans une interface différente.
Les interfaces définissent un contrat entre les classes implémentant les interfaces et leurs clients. Ils sont utilisés comme mécanisme d'abstraction afin que les clients puissent manipuler des "trucs ayant un comportement donné".
Donc, la réponse générale à la question "dois-je créer et utiliser cette interface?" est: Oui, si vous pouvez associer un (un seul) concept sémantiquement pertinent pour vos clients.
Par exemple, Comparable est une bonne interface, car il explique que les choses peuvent être comparées grâce à l'une de leurs méthodes, et en tant que client, je suis intéressé à traiter des objets comparables (par exemple pour les trier). A contrario, CoolStuff n'est pas une bonne interface si vous admettez que les objets sympas n'ont pas un comportement spécifique (en fait, vous pouvez imaginer un logiciel dans lequel traiter des objets sympas a du sens, car ils ont un comportement commun tel qu'un beCool méthode).
Dans votre cas particulier, je pense que votre interface est inutile. Qui l'utilisera, comment et quand? Vous ne pouvez pas créer une interface pour chacune des valeurs mutables. Alors demandez-vous quelle est la propriété pertinente et intéressante derrière vos méthodes.
Si ce que vous voulez, c'est traiter des objets ayant toutes leurs valeurs mutables accessibles via quelques méthodes, jetez un œil à la notion de bean Java et à la façon dont vous pouvez forcer vos classes à adopter leurs conventions.
Comme l'a dit Michael, n'ajoutez pas d'interface sauf si vous en avez un besoin spécifique.
Les tests sont un exemple de bonne raison. Bien que je préfère utiliser de vrais collaborateurs s'ils ne sont que des "objets de valeur" comme vous les appelez, pour une véritable isolation des tests unitaires, vous devrez peut-être créer un faux objet pour les tests, auquel cas une interface est très utile.
Les interfaces n'ont pas été nécessaires pour utiliser des cadres de simulation depuis des lustres.
Michael Borgwardt
On dirait que vous préconisez le monkeypatching. J'ai été dans cette voie avec Moles en C # et ce n'est pas joli. Mieux vaut passer dans vos collaborateurs si possible.
jhewlett
1
Bien que les deux frameworks mocking que j'utilise Mockito et easyMock ne puissent pas se moquer des classes finales lorsqu'ils sont immuables.
Archimedes Trajano
1
Si vous souhaitez que cet objet ait une sorte de validation des champs à l'avenir, vous devez les encapsuler à un stade précoce.
L '«interface pour l'objet de valeur» est ce que j'ai l'habitude d'appeler un accesseur.
J'ai expérimenté différentes politiques concernant les besoins des accesseurs. Certaines personnes préconisent autant que possible, d'autres interdisent alors de réduire la quantité de code à écrire.
Certains rationnels pour les accesseurs (ou utilisation à valeur directe) sont les suivants:
Les accesseurs permettent de changer plus tard la façon dont la valeur est stockée
Les accesseurs permettent d'ajouter un journal d'accès lorsque vous souhaitez déboguer votre logiciel (lorsque vous ajoutez un appel de journal dans une seule méthode, vous capturez chaque changement de valeur)
Les accesseurs sont plus en phase avec la programmation d'objets, chaque variable étant encapsulée par des méthodes
Les accesseurs réduisent l'expressivité du code (plus de SLOC pour le même résultat)
Les accesseurs prennent du CPU
Je préconise personnellement de réduire le nombre d'accesseurs et de les utiliser lorsque vous vous attendez à ce que le setter (setName) devienne plus qu'une simple affectation plus tard.
Ce type d'objet de valeur est de niveau assez bas. Je suggérerais de le pousser dans l'une des deux directions: (1) rendre l'objet de valeur immuable, c'est-à-dire, comme une valeur réelle , ou, (2) élever la mutabilité à une fonction commerciale orientée domaine de niveau supérieur, ce qui signifie que nous devrions exposer interfaces en termes d'unités de fonctionnalité pertinentes pour le domaine.
La création d'une interface est correcte, mais PAS la façon dont fonctionne votre exemple. Vous devez supprimer le setter de l'interface, et ça ira:
Cela permet de nombreuses implémentations différentes de celui-ci, comme le nom peut être récupéré de la base de données ... Setter doit être dans une interface différente.
la source
Les interfaces définissent un contrat entre les classes implémentant les interfaces et leurs clients. Ils sont utilisés comme mécanisme d'abstraction afin que les clients puissent manipuler des "trucs ayant un comportement donné".
Donc, la réponse générale à la question "dois-je créer et utiliser cette interface?" est: Oui, si vous pouvez associer un (un seul) concept sémantiquement pertinent pour vos clients.
Par exemple, Comparable est une bonne interface, car il explique que les choses peuvent être comparées grâce à l'une de leurs méthodes, et en tant que client, je suis intéressé à traiter des objets comparables (par exemple pour les trier). A contrario, CoolStuff n'est pas une bonne interface si vous admettez que les objets sympas n'ont pas un comportement spécifique (en fait, vous pouvez imaginer un logiciel dans lequel traiter des objets sympas a du sens, car ils ont un comportement commun tel qu'un beCool méthode).
Dans votre cas particulier, je pense que votre interface est inutile. Qui l'utilisera, comment et quand? Vous ne pouvez pas créer une interface pour chacune des valeurs mutables. Alors demandez-vous quelle est la propriété pertinente et intéressante derrière vos méthodes.
Si ce que vous voulez, c'est traiter des objets ayant toutes leurs valeurs mutables accessibles via quelques méthodes, jetez un œil à la notion de bean Java et à la façon dont vous pouvez forcer vos classes à adopter leurs conventions.
la source
Comme l'a dit Michael, n'ajoutez pas d'interface sauf si vous en avez un besoin spécifique.
Les tests sont un exemple de bonne raison. Bien que je préfère utiliser de vrais collaborateurs s'ils ne sont que des "objets de valeur" comme vous les appelez, pour une véritable isolation des tests unitaires, vous devrez peut-être créer un faux objet pour les tests, auquel cas une interface est très utile.
la source
Si vous souhaitez que cet objet ait une sorte de validation des champs à l'avenir, vous devez les encapsuler à un stade précoce.
la source
L '«interface pour l'objet de valeur» est ce que j'ai l'habitude d'appeler un accesseur.
J'ai expérimenté différentes politiques concernant les besoins des accesseurs. Certaines personnes préconisent autant que possible, d'autres interdisent alors de réduire la quantité de code à écrire.
Certains rationnels pour les accesseurs (ou utilisation à valeur directe) sont les suivants:
Je préconise personnellement de réduire le nombre d'accesseurs et de les utiliser lorsque vous vous attendez à ce que le setter (setName) devienne plus qu'une simple affectation plus tard.
la source
Ce type d'objet de valeur est de niveau assez bas. Je suggérerais de le pousser dans l'une des deux directions: (1) rendre l'objet de valeur immuable, c'est-à-dire, comme une valeur réelle , ou, (2) élever la mutabilité à une fonction commerciale orientée domaine de niveau supérieur, ce qui signifie que nous devrions exposer interfaces en termes d'unités de fonctionnalité pertinentes pour le domaine.
la source