Смішно, це питання просто нагадало мені таку саму розмову, яку я мав з одним із наших інженерів про бібліотеку комунікацій, над якою я працював.
Замість команд у мене були класи Request, а потім у мене були RequestHandlers. Дизайн був дуже схожий на те, що ви описуєте. Я думаю, що частиною вашої плутанини є те, що ви бачите англійське слово "командування" і миттєво думаєте "дієслово, дія ... тощо".
Але в цій конструкції подумайте про команду (або запит) як на лист. Або для тих, хто не знає, що таке поштова служба, подумайте електронною поштою. Це просто вміст, відокремлений від того, як слід діяти з цим вмістом.
Навіщо ти це робив? У більшості простих випадків у шаблону команд немає причин, і ви могли б змусити цей клас виконувати роботу безпосередньо. Однак робити роз'єднання, як у вашому дизайні, має сенс, якщо ваша дія / команда / запит повинна пройти деяку відстань. Наприклад, через розетки або труби або між доменом та інфраструктурою. Або, можливо, у вашій архітектурі ваші команди повинні бути стійкими (наприклад, обробник команд може виконувати 1 команду за один раз, через деякі системні події надходить 200 команд і після перших 40 процесів відбувається відключення). У такому випадку, маючи простий клас, призначений лише для повідомлення, стає дуже просто серіалізувати лише частину повідомлення в JSON / XML / бінарний / будь-яку іншу та передати її вниз по конвеєру, поки її командний обробник не буде готовий обробити її.
Ще одна перевага роз’єднання Command від CommandHandler полягає в тому, що тепер у вас є можливість паралельної ієрархії успадкування. Наприклад, усі ваші команди можуть виходити з базового класу команд, який підтримує серіалізацію. І, можливо, у вас є 4 з 20 командних обробників, які мають багато подібності, тепер ви можете отримати їх з базового класу прийшов обробник. Якби ви мали керувати даними та командами в одному класі, цей тип відносин швидко вийшов би з-під контролю.
Іншим прикладом для розв’язки може бути, якщо вашій команді потрібно було дуже мало введення (наприклад, 2 цілих числа та рядок), але логіка обробки була досить складною, де ви хочете зберігати дані у змінних проміжних членів. Якщо ви ставите в чергу 50 команд, ви не хочете виділяти пам'ять для всього цього проміжного сховища, тому ви відокремлюєте Command від CommandHandler. Тепер ви ставите в чергу 50 легких структур даних, і більш складне зберігання даних виділяється лише один раз (або N разів, якщо у вас є N обробників) командою CommandHandler, яка обробляє команди.