J'ai une partie du modèle CQRS implémentée à l'aide de l' architecture S # arp comme ceci:
public class MyCommand
{
public CustomerId { get; set; }
// some other fields
}
public class MyCommandHandler<MyCommand> : ICommandHandler<MyCommand, CommandResult>
{
Handle(MyCommand command)
{
// some code for saving Customer entity
return CommandResult.Success;
}
}
Je me demande pourquoi ne pas simplement avoir une classe Command
contenant à la fois des données et une méthode de gestion? Est-ce une sorte d'avantage de testabilité, où vous devez tester la logique de gestion des commandes séparément des propriétés des commandes? Ou est-ce une exigence commerciale fréquente, où vous devez avoir une commande gérée par différentes implémentations de ICommandHandler<MyCommand, CommandResult>
?
c#
design-patterns
architecture
cqrs
rgripper
la source
la source
Réponses:
Drôle, cette question m'a juste rappelé exactement la même conversation que j'ai eue avec l'un de nos ingénieurs à propos de la bibliothèque de communications sur laquelle je travaillais.
Au lieu de commandes, j'avais des classes Request et ensuite des RequestHandlers. Le design ressemblait beaucoup à ce que vous décrivez. Je pense qu'une partie de la confusion que vous avez est que vous voyez le mot anglais "command", et pensez instantanément "verb, action ... etc".
Mais dans cette conception, considérez la commande (ou la demande) comme une lettre. Ou pour ceux qui ne savent pas ce qu'est un service postal, pensez au courrier électronique. Il s'agit simplement d'un contenu, découplé de la manière dont ce contenu doit être appliqué.
Pourquoi voudriez-vous faire cela? Dans la plupart des cas simples, le modèle de commande n'a aucune raison et vous pouvez demander à cette classe d'effectuer le travail directement. Cependant, faire le découplage comme dans votre conception est logique si votre action / commande / demande doit parcourir une certaine distance. Par exemple, à travers, des sockets ou des tuyaux, ou entre le domaine et l'infrastructure. Ou peut-être que dans votre architecture, vos commandes doivent être persistantes (par exemple, le gestionnaire de commandes peut exécuter 1 commande à la fois, en raison de certains événements système, 200 commandes arrivent et après l'arrêt des 40 premiers processus). Dans ce cas, ayant une classe simple message uniquement, il devient très simple de sérialiser uniquement la partie message en JSON / XML / binaire / quoi que ce soit et de le transmettre dans le pipeline jusqu'à ce que son gestionnaire de commandes soit prêt à le traiter.
Un autre avantage du découplage de Command de CommandHandler est que vous avez maintenant la possibilité de disposer d'une hiérarchie d'héritage parallèle. Par exemple, toutes vos commandes peuvent dériver d'une classe de commandes de base qui prend en charge la sérialisation. Et peut-être que vous avez 4 gestionnaires de commande sur 20 qui ont beaucoup de similitudes, maintenant vous pouvez les dériver de la classe de base de gestionnaire venu. Si vous deviez gérer les données et les commandes dans une seule classe, ce type de relation deviendrait rapidement incontrôlable.
Un autre exemple de découplage serait si votre commande nécessitait très peu d'entrée (par exemple 2 entiers et une chaîne) mais que sa logique de gestion était suffisamment complexe pour que vous souhaitiez stocker des données dans les variables de membre intermédiaire. Si vous mettez en file d'attente 50 commandes, vous ne voulez pas allouer de mémoire pour tout ce stockage intermédiaire, vous séparez donc Command de CommandHandler. Maintenant, vous mettez en file d'attente 50 structures de données légères et le stockage de données plus complexe n'est alloué qu'une seule fois (ou N fois si vous avez N gestionnaires) par le CommandHandler qui traite les commandes.
la source
Le modèle de commande normal consiste à avoir les données et le comportement dans une seule classe. Ce type de «modèle de commande / gestionnaire» est légèrement différent. Le seul avantage par rapport au modèle normal est l'avantage supplémentaire de ne pas faire dépendre votre commande des frameworks. Par exemple, votre commande peut avoir besoin d'un accès DB, elle doit donc avoir une sorte de contexte ou de session DB, ce qui signifie qu'elle dépend des frameworks. Mais cette commande peut faire partie de votre domaine, vous ne voulez donc pas qu'elle dépende des frameworks selon le principe d'inversion de dépendance . Séparer les paramètres d'entrée et de sortie du comportement et avoir un répartiteur pour les câbler peut résoudre ce problème.
D'un autre côté, vous perdrez à la fois l'héritage et la composition des commandes. Je pense que c'est le vrai pouvoir.
Aussi, minuscule piqûre. Ce n'est pas parce qu'il a Command dans son nom qu'il fait partie du CQRS. Il s'agit de quelque chose de beaucoup plus fondamental. Ce type de structure peut servir à la fois de commande et de requête même en même temps.
la source