Divertente, questa domanda mi ha appena ricordato esattamente la stessa conversazione che ho avuto con uno dei nostri ingegneri sulla libreria di comunicazioni su cui stavo lavorando.
Al posto dei comandi, avevo le classi Request e poi avevo RequestHandlers. Il design era molto simile a quello che stai descrivendo. Penso che parte della confusione che hai è che vedi la parola inglese "command", e immediatamente pensi "verb, action ... etc".
Ma in questo disegno, pensa a Comando (o Richiesta) come una lettera. O per quelli che non sanno che cos'è un servizio postale, pensa alla posta elettronica. È semplicemente contenuto, disaccoppiato dal modo in cui il contenuto dovrebbe essere interpretato.
Perché dovresti farlo? Nella maggior parte dei casi semplici, di Command Pattern non vi è alcun motivo e si potrebbe avere questa classe eseguire il lavoro direttamente. Tuttavia, fare il disaccoppiamento come nel tuo progetto ha senso se la tua azione / comando / richiesta deve percorrere una certa distanza. Ad esempio, across, socket o pipe o tra dominio e infrastruttura. O forse nella tua architettura i tuoi comandi devono essere persistenti (ad esempio, il gestore di comandi può eseguire 1 comando alla volta, a causa di alcuni eventi di sistema, arrivano 200 comandi e dopo che i primi 40 processi vengono arrestati). In tal caso, avendo una semplice classe di solo messaggio diventa molto semplice serializzare solo la parte del messaggio in JSON / XML / binary / qualunque e passarla lungo la pipeline fino a quando il suo gestore di comandi è pronto per elaborarla.
Un altro vantaggio del comando disaccoppiamento di CommandHandler è che ora hai l'opzione della gerarchia di ereditarietà parallela. Ad esempio, tutti i comandi potrebbero derivare da una classe di comando di base che supporta la serializzazione. E forse hai 4 gestori di comandi su 20 che hanno molte somiglianze, ora puoi ricavarne quelli della classe base di handler venuti. Se dovessi avere dati e gestione dei comandi in una classe, questo tipo di relazione verrebbe rapidamente fuori controllo.
Un altro esempio per il disaccoppiamento sarebbe se il comando richiedesse un input molto piccolo (ad esempio 2 interi e una stringa), ma la sua logica di gestione era abbastanza complessa in cui si desidera memorizzare i dati nelle variabili membro intermedie. Se si accodano 50 comandi, non si desidera allocare memoria per tutto lo storage intermedio, quindi separare Command da CommandHandler. Ora accodate 50 strutture di dati leggeri e una più complessa archiviazione dei dati viene assegnata una sola volta (o N volte se avete N gestori) da CommandHandler che sta elaborando i comandi.