¿Cuál es la diferencia entre Command + CommandHandler y Service?


He estado leyendo sobre el uso de objetos de comando para representar casos de uso que nuestro dominio expone, y objetos de Controlador de comandos para procesar esos comandos.

Por ejemplo:

  • RegisterUserCommand
  • RegisterUserCommandHandler

Pero se ve exactamente igual que tener un RegisterUserService, donde el objeto command representaría los parámetros del método registerUser().

Y por supuesto, si el método tuviera demasiados parámetros, terminaría creando un objeto para envolverlos y ese objeto sería lo mismo que el RegisterUserCommand.

Entonces, ¿por qué tener un patrón diferente para representar la misma cosa? Los servicios están muy extendidos, no los Comandos (según mi experiencia); ¿cuál es la diferencia aquí que me estoy perdiendo? En resumen, ¿por qué usaría uno en lugar del otro?

Author: Dave Schweisguth, 2014-06-29

2 answers

Tener comandos te da los beneficios del viejo patrón de comandos:

  • puede parametrizar un objeto, por ejemplo, un elemento de interfaz de usuario, con un comando para realizar
  • puede almacenar un comando y ejecutarlo más tarde, por ejemplo, en una cola o en un registro de transacciones
  • puede realizar un seguimiento de los comandos que ejecutó, lo que le da una base para implementar undo

Si sus servicios eran grandes, cada uno con muchos métodos complejos (y si los métodos no eran complejos, probablemente no debería usar DDD o CQRS), luego mover cada método a un Controlador de comandos podría mejorar su aplicación al hacerla más componible, más fácil de probar, etc. Sin duda, es común que las personas que refactorizan directamente de los grandes servicios a los Comandos/Controladores de comandos consideren esto como un beneficio del último patrón. Pero podría obtener el mismo beneficio descomponiendo servicios grandes en servicios más pequeños( como sugiere el servicio muy específico en su ejemplo), por lo que estrictamente hablando no es un diferencia entre servicios y Comandos / Manejadores de comandos.

 17
Author: Dave Schweisguth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-29 16:30:48

Creo que tienes toda la razón al cuestionar que estos dos conceptos parecen ser similares en contexto. Probablemente vale la pena volver atrás y considerar, prácticamente, para qué están destinados.

Servicios DDD

En el Diseño impulsado por Dominio, hay diferentes tipos de servicios por ejemplo, Servicios de Aplicaciones (comúnmente servicios de interfaz de usuario), Servicios de Infraestructura y Servicios de Dominio.

Jimmy Bogard hace un excelente trabajo al explicar estos

En a en pocas palabras:

Servicios de dominio

El trabajo de los servicios de dominio es ejecutar una funcionalidad que normalmente no se adapta a una entidad. Considere usar un servicio de dominio cuando tenga una funcionalidad que requiera una variedad de
entidades (objetos agregados / valor). Un ejemplo tal vez: para calcular una estimación de cuánto puede costar una hipoteca, se requiere el detalle de los ingresos / empleo del comprador. Usted puede requerir el historial de crédito del comprador y finalmente usted puede necesitar información sobre el edificio para el que se está considerando la hipoteca.

pricingService.CalculateMortageEstimate(BuyerIncomingDetails bid, BuyerCreditHistory bch, BuildingOverview bo)

Servicios de aplicaciones

Un ejemplo tal vez los servicios utilizados como parte de la interfaz de usuario.

Servicios de infraestructura

Servicios que tienden a comunicarse con recursos externos (remitentes de correo electrónico, sistemas de archivos, archivos xml, ftp, etc...)

Command / CommandHandlers (CQRS)

Segregación de Responsabilidades de Consulta de Comandos. Como dice en la lata; una separación de:

  1. ejecución de consultas en su fuente de datos
  2. Modificando (a través de comandos) sus datos

Usar CQRS no siempre es la opción correcta, pero en mi experiencia, las personas tienden a usarlo cuando sus datos se distribuyen a través de múltiples fuentes de datos.

Así que con los comandos, está pidiendo explícitamente que se ejecute una unidad de trabajo (que no debe confundirse con el patrón UnitOfWork), por ejemplo, AddFraudRecordCommand o UpdateNoteCommand.


Con eso poco refresco sobre las diferencias entre los servicios DDD y los comandos CQRS. Me gustaría señalar las siguientes cosas:

  1. ¿Necesito siquiera Command / CommandHandlers? ¿Qué estoy ganando, debo ir directamente a los servicios?

  2. El trabajo de mi Controlador de Comandos es manejar la lógica de mi comando (un Comando es una Solicitud muy específica). Considerando que los servicios DDD tienen diferentes trabajos (Servicios de dominio: funcionalidad de coordenadas de múltiples entidades, Infraestructura Servicios: colaborar con servicios externos, por ejemplo, correo electrónico)

  3. Tal vez pensar en ello de esta manera: CommandHandler Job-ejecutar el código para ejecutar el comando específico (esto puede incluir el uso de varios servicios). Servicio de Trabajo – Dependiendo de qué tipo de servicio es.

No es el mejor ejemplo, pero espero que arroje alguna luz sobre lo que estoy tratando de decir:

public class CalculateFraudProbabilityCommandHandler : CommandHandler<CalculateFraudProbabilityCommand>
{
         IFraudService _fraudService;
         IEmailNotifier _notifier;
         ICustomerRepository _customerRepo;


  public CalculateFraudProbabilityCommandHandler(ICustomerRepository customerRepo, IFraudService fraudService, IEmailNotifier notifier) 
  {     
        _fraudService = fraudService; //Domain Service  
        _notifier = notifier;         //Infrastructure Service  
        _customerRepo = customerRepo; //Repository
  }

 //Execute Command
 public void Execute(CalculateFraudProbabilityCommand command) {

     Customer customer = _customerRepository.GetById(command.CustomerId);
     FraudHistory fraudHistory = _fraudService.RetrieveFraudHistory(customer);

     //any fraud recently? if so, let someone know!
      if(fraudHistory.FraudSince(DateTime.Now.AddYear(-1)) {
           _notifier.SendEmail(_fraudService.BuildFraudWarningEmail(customer,      fraudHistory));
      }     

   }

}
 11
Author: Mike,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-06 09:31:18