Es curioso, esta pregunta me recordó exactamente la misma conversación que tuve con uno de nuestros ingenieros sobre la biblioteca de comunicaciones en la que estaba trabajando.
En lugar de comandos, tuve clases de Request y luego tuve RequestHandlers. El diseño se parecía mucho a lo que estás describiendo. Creo que parte de la confusión que tienes es que ves la palabra inglesa "comando", y al instante piensas "verbo, acción ... etc.".
Pero en este diseño, piense en Command (o Request) como una carta. O para aquellos que no saben qué es un servicio postal, piense en el correo electrónico. Es simplemente contenido, desacoplado de cómo se debe actuar sobre ese contenido.
¿Por qué harías esto? En la mayoría de los casos simples, del Patrón de comando no hay razón y puede hacer que esta clase realice el trabajo directamente. Sin embargo, hacer el desacoplamiento como en su diseño tiene sentido si su acción / comando / solicitud debe recorrer cierta distancia. Por ejemplo, a través de enchufes o tuberías, o entre dominio e infraestructura. O tal vez en su arquitectura sus comandos deben ser persistentes (por ejemplo, el controlador de comandos puede hacer 1 comando a la vez, debido a algunos eventos del sistema, llegan 200 comandos y después del cierre de los primeros 40 procesos). En ese caso, al tener una clase simple de solo mensaje, se vuelve muy simple serializar solo la parte del mensaje en JSON / XML / binary / whatever y pasarlo por la tubería hasta que su controlador de comandos esté listo para procesarlo.
Otra ventaja de desacoplar Command de CommandHandler es que ahora tiene la opción de jerarquía de herencia paralela. Por ejemplo, todos sus comandos podrían derivar de una clase de comando base que admita la serialización. Y tal vez tenga 4 de 20 manejadores de comandos que tengan mucha similitud, ahora puede derivarlos de la clase base de manejador vino. Si tuviera que manejar datos y comandos en una clase, este tipo de relación se descontrolaría rápidamente.
Otro ejemplo para el desacoplamiento sería si su comando requiriera muy poca entrada (por ejemplo, 2 enteros y una cadena), pero su lógica de manejo era lo suficientemente compleja como para almacenar datos en las variables miembro intermedias. Si pone en cola 50 comandos, no desea asignar memoria para todo ese almacenamiento intermedio, por lo que separa Command de CommandHandler. Ahora puede poner en cola 50 estructuras de datos livianas y el almacenamiento de datos más complejo se asigna solo una vez (o N veces si tiene N controladores) por el CommandHandler que procesa los comandos.