Les entités Java D'entreprise devraient-elles être stupides?

Dans notre application Java EE héritée, il existe des charges de classes d'objets de valeur (VO) qui ne contiennent généralement que des getters et des setters, peut-être equals() et hashCode(). Ce sont (généralement) les entités à enregistrer dans le stockage de persistance. (Pour mémoire, notre application n'a pas D'EJB-bien que puisse changer dans le futur -, et nous utilisons Hibernate pour persister nos entités.) Toute la logique métier pour manipuler les données dans VOs Est dans des classes séparées (pas EJBs, juste POJOs). Mon état d'esprit oo déteste ceci, car je crois que les opérations sur une classe donnée devraient résider dans cette même classe. J'ai donc envie de refactoriser pour déplacer la logique dans les VOs connexes.

Je viens d'avoir une discussion avec un collègue qui est beaucoup plus expérimenté en Java EE que moi, et il a confirmé que les entités stupides étaient au moins la voie recommandée. Cependant, il a également lu récemment des avis qui remettent en question la validité de cette position.

Je comprends qu'il y a des problèmes qui au moins limitent ce qui peut être mis dans une classe d'entité:

  • Il ne devrait pas avoir de dépendance directe à la couche de données (par exemple, le code de requête devrait plutôt aller dans des Dao séparés)
  • si elle est directement exposée à des couches supérieures ou au client (par exemple via SOAP), Son interface peut devoir être limitée

, y a plus de raisons valables pas pour déplacer logique dans mes entités? Ou d'autres préoccupations à prendre en compte?

26
demandé sur Arjan Tijms 2010-02-25 13:40:25

8 réponses

Les DTO et VO sont censés être utilisés pour transférer des données et ne pas intégrer de logique. Les objets métier d'autre part sont censés intégrer une certaine logique. Je dis certains , car il y a toujours un équilibre à trouver entre ce que vous mettez dans les services qui coordonnent la logique impliquant plusieurs objets métier et ce que vous mettez dans les objets métier eux-mêmes. La logique typique dans les objets métier peut être la validation, le calcul de champ ou toute autre opération qui impact sur un seul objet métier à la fois.

Notez que je n'ai pas mentionné le terme entité jusqu'à présent. Les entités persistantes ont été popularisées avec ORM et nous essayons aujourd'hui d'utiliser des entités persistantes à la fois comme DTO et objet métier en même temps. Autrement dit, l'entité elle-même circule entre les couches et les niveaux, et contient une certaine logique.

Y a-t-il d'autres raisons valables de ne pas pour déplacer la logique dans mes entités? Ou tout d'autres préoccupations à prendre en compte?

Comme vous l'avez souligné, tout est une question de dépendances et de ce que vous exposez. Tant que les entités sont muettes (proches de DTO), elles peuvent être isolées facilement dans un jar dédié qui sert d'API de la couche . Plus vous mettez de logique dans les entités, plus il devient difficile de le faire. Faites attention à ce que vous exposez et à ce dont vous dépendez (la charge de la classe, le client devra également avoir la classe depend). Cela s'applique aux exceptions, à la hiérarchie d'héritage, etc.

Juste pour donner un exemple, j'avais un projet où les entités avaient une méthode toXml(...) utilisé dans la couche de gestion. En conséquence, le client des entités dépendait de XML.

Mais si vous ne vous souciez pas trop des couches, et de la séparation stricte entre L'API et l'implémentation, je pense qu'il est bon de déplacer une certaine logique dans les entités.

Modifier

Cette question a été discutée plusieurs fois et continuera probablement à être discutée car il n'y a pas de définitive réponse. Quelques liens intéressants:

17
répondu ewernli 2010-02-25 13:31:39

Je pense que votre point est valide.
Voir ceci pour plus - http://martinfowler.com/bliki/AnemicDomainModel.html
Avec JPA, les entités sont des objets légers. Donc, je ne pense pas que ce soit un problème d'avoir de la logique en eux.

En cas d'utilisation avec SOAP/Web Services, j'ajouterais une couche de façade séparée.

8
répondu Padmarag 2010-02-25 10:46:46

Au-delà de L'article de Fowler mentionné précédemment, il y a un traité complet sur les modèles de domaines riches et anémiques dans le livre D'Eric Evans Domain Driven Design(2004).

Aussi, découvrez http://dddcommunity.org/

4
répondu Matthew Flynn 2011-04-16 08:49:15

Bon, voici un résumé des commentaires que J'ai reçus de mon formateur Java EE.

D'un point de vue pratique, trouver un compromis entre domaine anémique et riche en déplaçant la logique ne devrait pas poser de problème tant que les méthodes fonctionnent avec les attributs de l'entité. Quand il s'agit d'un domaine riche, la ligne doit être tracée quelque part et apparemment Fowler et King ont émis des commentaires dans cette direction.

Par exemple, considérons une méthode calculateInterestRate () dans un BankAccount qui récupère des informations à partir d'autres objets de domaine comme la vérification de combien de temps quelqu'un a été un client. Pour éviter la dépendance, on peut diviser la méthode entre les objets, mais cette approche signifie que le code peut finir par être éparpillé entre plusieurs classes. À ce stade, on pourrait aussi bien faire une classe InterestCalculator.

Une autre chose à prendre en compte est la sécurité des threads. Les Dao Singleton et les Services gérés par Spring doivent être thread safe alors que tout ce qui se trouve dans le modèle de domaine le sera être exposé à des problèmes de concurrence.

Enfin, il y a le problème de la maintenance. Êtes-vous sûr que vous serez autour de maintenir l'application dans quelques années? Les choix que vous faites peuvent sembler justifiés mais Êtes-vous certain que le prochain développeur aura l'expertise nécessaire pour comprendre facilement votre code?

3
répondu James P. 2010-02-26 16:52:44

La convention à laquelle vous faites référence est d'adopter un modèle de domaine anémique, par opposition au modèle de domaine riche, où les entités sont de simples POJOs annotés en beans (@Entity) avec juste le strict minimum en termes de getters et setters. Ainsi, une classe avec une méthode toXML () serait considérée comme un domaine riche. Je suppose que cela aide à garder une vue claire de ce qui est mappé à une base de données relationnelle même si la granularité diffère.

L'avantage est qu'il y a une séparation claire entre la logique et données (c'est là que la philosophie OO est brisée). L'approche consiste à les regrouper en classes ou Services de logique métier. Ceci est selon une architecture en couches avec des couches respectives étant Domain, Services, DAO et UI.

C'est la théorie.

Edit: juste pour clarifier, quand je dis qu'il y a une séparation claire entre la logique et les données, je veux dire qu'un objet est orienté données et un autre est orienté méthode d'une manière qui pourrait être considérée comme un retour à la procédure.

1
répondu James Poulson 2010-02-25 16:48:25

Le principal problème avec l'ajout de logique à ces classes est qu'elles auraient besoin de plus d'attributs pour suivre l'état de l'objet, et ces attributs supplémentaires n'ont généralement pas besoin d'être sérialisés. Cela signifie un travail supplémentaire est nécessaire dans le mécanisme de sérialisation de ces classes.

Considérant que de nombreux projets ont un mélange de programmeurs jr. et de programmeurs sr. et que la plupart du travail est effectué par les jr qui ne comprennent pas (ou ne se soucient pas ) de la sérialisation optimale, c'est beaucoup plus facile d'avoir ces vieux objets java comme "objets de valeur" qui passent et reçoivent des données et mettent la logique à un autre endroit.

Si vous parvenez à avoir une architecture où la logique est placée dans un objet métier ( C'est-à-dire Vo + Logic), je pense que ce serait mieux aussi. Gardez à l'esprit que toute l'équipe est dans la même page et qu'elle ne duplique pas le code et la logique (ce qui n'arrive jamais non? )

Réponse courte: non, ils ne devraient pas toujours être stupides, mais c'est beaucoup plus facile de cette façon.

1
répondu OscarRyz 2010-02-25 17:00:54

J'ai fait de la programmation C et bien que la POO soit agréable pour simplifier les problèmes en construisant des hiérarchies de classes, je trouve toujours l'approche C simple la plus simple et la plus grande dans de nombreux cas. En C, nous avons des structures avec seulement des membres publics, et le programmeur passe de telles structures à des fonctions (en Java, de telles fonctions seraient par exemple des fonctions statiques dans une classe utilitaire) dont les fonctions manipulent les membres. Les données et l'algorithme sont séparés car les fonctions ne sont pas des structures. J'ai toujours eu le sentiment que les objets VO sont comme des structures en C.

Il y a beaucoup de cas où le langage C n'est pas le plus grand, parce que par exemple il n'y a pas de hiérarchie, il n'y a pas de polymorphisme, des choses que les programmeurs OOP décents trouvent utiles. Cependant, en général, j'aime cette approche C simple et préfère l'utiliser à moins que je sache qu'une technique de POO serait vraiment bénéfique. Par exemple, lorsque j'ai besoin d'utiliser une hiérarchie de classes pour modéliser quelque chose ou que je dois m'assurer que les membres de une ou plusieurs classes (dans une hiérarchie) sont toujours cohérentes les unes avec les autres alors je ne peux pas utiliser l'approche c struct. Mais dans ces cas, je n'aurais pas seulement des setters et des getters de toute façon.

Je référerais aussi cet article qui parle de C++ mais j'aime comment ce gars explique de telles choses: http://www.gotw.ca/gotw/084.htm Cet article a 2 règles sur le moment de faire une fonction le membre d'une classe:

(de la citation ci-dessous, je laisse de côté certaines choses, lisez l'original Si vous vous voulez tout voir)

  1. Toujours en faire un membre s'il doit en être un: quelles opérations doivent être membres, parce que le langage C++ le dit simplement (par exemple, les constructeurs) ou pour des raisons fonctionnelles (par exemple, ils doivent être virtuels)? S'ils doivent l'être, alors Oh bien, ils doivent juste l'être; affaire classée.

  2. Préférez en faire un membre s'il a besoin d'un accès aux internes: quelles opérations ont besoin d'un accès aux données internes que nous aurions autrement à accorder via friendship? Ceux-ci devraient normalement être membres.

Dans tous les autres cas, préférez en faire un non-ami non-membre: quelles opérations peuvent fonctionner aussi bien que non-ami non-membre? Ceux-ci peuvent, et devraient donc normalement, être des non-membres. Cela devrait être le cas par défaut à atteindre.

J'ai le sentiment que si vous avez des doutes quant à l'ajout de fonctions à ces classes, vous n'avez pas vraiment besoin de le faire. Ce que j'ai écrit ici n'est qu'une partie de toutes les raisons pour lesquelles je pas ajouter des méthodes à de telles classes mais peut-être que c'est le père de toutes mes autres raisons. Mais tout cela est subjectif si YMMV. BTW l'approche static utility functions rend les tests unitaires simples dans la plupart des cas.

0
répondu bjdodo 2013-06-13 17:45:55

Les entités

Sont fréquemment générées. Dans des langages comme Java, il n'y a pas de classe partielle, donc nous ne pouvons pas étendre une entité (sans considérer les modèles comme Visitor). Lorsque vous avez besoin de régénérer vos entités, vous devrez ajouter la logique métier nouveau, qui n'est pas du tout pratique.

Avec les entités, je préfère opter pour une conception à haute cohésion entre les entités et leur logique.

D'autres questions à considérer sont le fait que toutes les opérations commerciales sur une entité est égale dans toutes les situations. En outre, autoriser la logique métier dans les entités tend à soumettre l'entité à un couplage avec des technologies d'intégration telles que XML qui, à mon avis, devraient être tenues à l'écart de la logique de domaine à tout moment. Dans une architecture onion, XML serait dans l'enveloppe externe et les objets de domaine dans l'intérieur, pour illustrer à quel point ils sont vraiment retirés les uns des autres si vous voulez créer un système enfichable réutilisable.

0
répondu Dormouse 2017-04-03 07:19:25