Забавно, этот вопрос только напомнил мне о том же разговоре, который у меня был с одним из наших инженеров о библиотеке коммуникаций, над которой я работал.
Вместо команд у меня были классы Request, а затем - RequestHandlers. Дизайн был очень похож на то, что вы описываете. Я думаю, что часть вашей путаницы в том, что вы видите английское слово «команда» и сразу же думаете «глагол, действие ... и т. Д.».
Но в этом проекте думайте о Команде (или Запросе) как о букве. Или для тех, кто не знает, что такое почтовый сервис, подумайте по электронной почте. Это просто контент, отделенный от того, как следует воздействовать на этот контент.
Зачем ты это делаешь? В большинстве простых случаев, в шаблонах команд нет причин, и вы могли бы заставить этот класс выполнять работу напрямую. Однако выполнение разделения, как в вашем проекте, имеет смысл, если ваше действие / команда / запрос должны пройти некоторое расстояние. Например, через сокеты или каналы, или между доменом и инфраструктурой. Или, возможно, в вашей архитектуре ваши команды должны быть постоянными (например, обработчик команд может выполнять по 1 команде за раз, из-за некоторых системных событий, поступает 200 команд и после завершения первых 40 процессов). В этом случае, имея простой класс только для сообщений, становится очень просто сериализовать только часть сообщения в JSON / XML / двоичный / что угодно и передавать его по конвейеру, пока обработчик команд не будет готов обработать его.
Другое преимущество отделения Command от CommandHandler заключается в том, что теперь у вас есть возможность параллельной иерархии наследования. Например, все ваши команды могут быть производными от базового класса команд, который поддерживает сериализацию. И, возможно, у вас есть 4 из 20 обработчиков команд, которые имеют большое сходство, теперь вы можете получить их из базового класса обработчика команд. Если бы вы обрабатывали данные и команды в одном классе, отношения такого типа быстро вышли бы из-под контроля.
Другим примером для развязки было бы, если вашей команде требовалось очень мало ввода (например, 2 целых числа и строка), но ее логика обработки была достаточно сложной, чтобы вы хотели хранить данные в переменных промежуточного члена. Если вы ставите в очередь 50 команд, вам не нужно выделять память для всего этого промежуточного хранилища, поэтому вы отделяете Command от CommandHandler. Теперь вы ставите в очередь 50 легких структур данных, а более сложное хранилище данных выделяется только один раз (или N раз, если у вас N обработчиков) с помощью CommandHandler, который обрабатывает команды.