Tout d'abord, je ne parle pas de validation dans le sens de la nullabilité ou de la longueur d'un champ comme dans this et ceci questions où nous pouvons utiliser des méthodes isvalid () dans les classes d'entreprise ou un validateur externe. Cependant, ma question est liée à la validation ou non dans les classes de l'entreprise. J'utilise un style d'architecture en couches avec des services consommant la couche de données de données et en interagissant avec le modèle de domaine.
Simplyez les exigences de domaine, supposons que j'ai des films et des critiques et que les utilisateurs ne peuvent effectuer qu'un seul examen par film. Ainsi, un deuxième examen est un objet valide, mais les règles commerciales ne doivent pas permettre la révision à remplir.
Donc, je pourrais faire:
ReviewService >> addReview(review,movie)
loggedUser = getLoggedUser()
review = reviewRepository.searchReviewFrom(loggedUser,movie)
if (review == null)
reviewRepository.save(review)
else
// some mechanism to inform the error, it could be NotificationPattern
Ou:
Movie >> addReview(review)
for r in this.reviews
if r.user = review.user
throw ReviewAlreadyUploaded
// if no expcetion is thrown
this.reviews.add(review)
Je pense que cette validation inerteviewPerUser est une règle d'entreprise pure et devrait aller dans les classes de l'entreprise, dans ce cas la classe de cinéma. Ainsi, les règles commerciales sont contenues le domaine et non dispersés entre les couches. Toutefois, si les listes d'examens des films sont grandes dans presque tous les cas, cette option implique une requête et instancier un grand nombre d'objets d'examen et itérer sur tous les éléments.
Supposons donc que j'ai choisi l'option 1, je dois vous assurer que chaque client qui souhaite créer un commentaire pour un film doit utiliser le service, car il peut casser la contrainte d'entreprise de 1 examen par utilisateur si, par exemple, utiliser directement le Revisitory. . Cela commence à sonner comme une couche de services avec toute la logique d'entreprise et une anémique avec des classes de domaine étant des sacs d'attributs pour transporter des données vers et depuis la base de données.
Où est la ligne qui sépare la logique commerciale qui devrait être sur des services de celui qui devrait être sur des classes de domaine.
Dans une application DDD (conception de domaine axée sur le domaine) à l'aide d'une architecture en couches classique, la logique commerciale va dans la couche domaine. Maintenant, veuillez noter que ce calque ne contient pas seulement les entités de domaine (Movie
, Review
), mais aussi services de domaine (comme un ReviewService
classe ) et des référentiels. Ainsi, ReviewService
est également une classe d'entreprise.
Votre préoccupation concernant chaque client ayant Pour utiliser la méthode d'entreprise appropriée (addReview
) n'est pas réaliste. Il n'existe tout simplement aucun moyen pratique d'éviter une classe client mal écrite de violation des règles commerciales, si les développeurs ne collent pas aux règles de l'architecture choisie. Par exemple, si Movie
a une méthode getReviews()
(ou a reviews
propriété) qui expose une collection mutable d'examens, le code client peut toujours ajouter une critique arbitraire. Et même si c'est immuable, le code du client peut toujours créer la base de données invalide Review
dans la base de données à l'aide d'un référentiel.
À mon avis, il est préférable de ne pas avoir que des méthodes commerciales relativement simples dans des entités domaines et généralement uniquement pour des opérations en lecture seule. La logique commerciale plus complexe est la mieux assignée à des classes de services de domaine cohésives. Sinon, vos cours d'entité deviendront rapidement trop gros et complexes. Ainsi, par exemple, une opération d'entreprise qui ajoute une critique de film sous réserve de règles de validation de l'entreprise serait mieux placée dans une classe de service de domaine ReviewMaintenance
ou même une classe ReviewCreation
si la "Ajout d'une critique" L'opération est suffisamment complexe.
Vous laissez la possibilité de restreindre l'entrée dans la base de données. S'il ne peut en effet être qu'un seul examen d'un film particulier par un utilisateur particulier, il devrait s'agir d'une contrainte de base de données. Si vous faites cela, alors votre préoccupation est de savoir comment gérer une tentative infructueuse d'insérer un deuxième examen - comment cela sera-t-il rapporté à l'utilisateur?.