DDD: où mettre la logique de persistance, et quand utiliser la cartographie ORM
nous examinons attentivement nos modèles D'application Web (Java). Dans le passé, nous avons souffert d'un modèle d'objet trop anémique et d'une séparation trop procédurale entre les contrôleurs, les services et les OAD, avec des objets de valeur simples (essentiellement des sacs de données) voyageant entre eux. Nous avons eu recours à la gestion déclarative (XML) de la MRO (hibernation) pour la persistance. Toute la gestion de l'entité a eu lieu dans les ofa.
En essayant de passer à un riche modèle de domaine, nous nous trouvons aux prises avec la meilleure façon de concevoir la couche de persistance. J'ai passé beaucoup de temps à lire et à réfléchir à des modèles de Design basés sur des domaines. Cependant, j'aimerais avoir quelques conseils.
tout d'abord, les choses sur lesquelles je suis le plus confiant:
nous aurons des controllers "minces" à l'avant qui ne traiteront que les formulaires de traitement HTTP et HTML, la validation, la logique de L'interface utilisateur.
nous aurons une couche de services de logique d'affaires apatrides qui met en œuvre des algorithmes ou logique, pas au courant de L'interface utilisateur, mais très au courant (et déléguant) le modèle de domaine.
nous aurons un modèle de domaine plus riche qui contient l'état, les relations, et la logique inhérente aux objets dans ce modèle de domaine.
la question vient autour de la persistance. Auparavant, nos services seraient injectés (via Spring) avec DAOs, et utiliseraient les méthodes DAO comme find() et save() pour effectuer la persistance. Cependant, un riche domaine modèle semblerait impliquer que les objets devraient savoir comment sauvegarder et supprimer eux-mêmes, et peut-être que les services de niveau supérieur devraient savoir comment localiser (requête pour) les objets de domaine.
ici, quelques questions et incertitudes se posent:
voulons-nous injecter DAOs dans des objets de domaine, pour qu'ils puissent faire "ceci.someDao.save ()" dans une méthode save ()? C'est un peu embarrassant car les objets domain ne sont pas des singletons, donc nous aurons besoin d'usines ou après la construction de réglage des DAOs. Lorsque vous chargez des entités à partir d'une base de données, cela devient compliqué. Je sais que le Printemps de l'AOP peut être utilisé pour cela, mais je ne pouvais pas le faire fonctionner (à l'aide de Jouer! cadre, une autre ligne d'expérimentation) et il semble assez salissant et magique.
conservons-nous plutôt des DAOs (référentiels)?) complètement séparé, à l'instar des apatrides logique d'entreprise de services? Cela peut donner un sens, mais cela signifie que si l'option "enregistrer" ou "supprimer" sont inhérents opérations de objet de domaine, l'objet de domaine ne peut pas les exprimer.
est-ce qu'on se contente de se passer entièrement de DAOs et d'utiliser JPA pour laisser les entités se gérer elles-mêmes.
Voici la prochaine subtilité: il est tout à fait pratique de cartographier les entités en utilisant JPA. Le Jeu! framework nous donne une classe de base d'entity agréable, aussi, avec des opérations comme save () et delete (). Toutefois, cela signifie que nos entités modèles de domaine sont très étroitement liées à la structure de la base de données, et nous sont des objets qui passent autour avec une grande quantité de logique de persistance, peut-être tout le chemin jusqu'à la couche de vue. Si rien d'autre, cela rendra le modèle de domaine moins réutilisable dans d'autres contextes.
si nous voulons éviter cela, alors nous avons besoin d'une sorte de mapping DAO-soit en utilisant JDBC simple (ou au moins Jdbctemplate de Spring), ou en utilisant une hiérarchie parallèle des entités de base de données et des entités "d'affaires", avec DAOs pour toujours copier l'information d'une hiérarchie à l'autre.
Quel est le choix de conception approprié ici?
Martin
2 réponses
vos questions et doutes sonnent une alarme intéressante ici, je pense que vous êtes allé un peu trop loin dans votre interprétation d'un "modèle de domaine riche". La richesse ne va pas jusqu'à sous-entendre que la logique de persistance doit être gérée par les objets du domaine, en d'autres termes, non, ils ne devraient pas savoir comment se sauver et se supprimer (au moins pas explicitement, bien que Hibernate ajoute en fait une certaine logique de persistance de manière transparente). C'est ce qu'on appelle souvent l'ignorance de la persistance.
je suggère que vous conserviez le système d'injection DAO existant (une bonne chose à avoir pour les tests unitaires) et laissiez la couche de persistance telle quelle tout en essayant de déplacer un peu de logique d'affaires vers vos entités d'où il fit. Un bon point de départ pour cela est d'identifier les agrégats et d'établir vos racines agrégées. Ils contiennent souvent plus de logique commerciale que les autres entités.
cependant, cela ne veut pas dire que les objets de domaine doivent contenir logique (surtout pas logique nécessaire pour de nombreux autres objets à travers l'application, qui appartient souvent dans les Services).
Je ne suis pas un expert en Java, mais J'utilise NHibernate dans mon code.Net pour que mon expérience soit directement transposable dans le monde Java.
lorsque vous utilisez ORM (comme Hibernate que vous avez mentionné) pour construire une application de conception par Domaine, une des bonnes (Je ne dirais pas meilleure) pratiques est de créer des soi-disant services d'application entre L'UI et le domaine. Ils sont similaires aux objets d'affaires apatrides que vous avez mentionnés, mais devraient contenir presque aucune logique. Ils devraient ressembler ceci:
public void SayHello(int id, String helloString)
{
SomeDomainObject target = domainObjectRepository.findById(id); //This uses Hibernate to load the object.
target.sayHello(helloString); //There is a single domain object method invocation per application service method.
domainObjectRepository.Save(target); //This one is optional. Hibernate should already know that this object needs saving because it tracks changes.
}
toute modification apportée aux objets contenus par DomainObject (ajout d'objets aux collections) sera gérée par Hibernate.
Vous aurez également besoin d'une sorte de AOP pour intercepter les invocations de la méthode de service d'application et créer la session D'hibernation avant que la méthode n'exécute et enregistre les modifications après la fin de la méthode sans exception.
Il y a un très bon exemple de comment le faire DDD en Java ici. Il est basé sur l'exemple de problème Eric Evans' "Livre Bleu". Le code d'échantillon de la classe logique d'application est ici.