Паттерн "Команда" в C# — объекты действий, а не методы
Краткий обзор паттерна есть в поведенческих паттернах. Здесь — практика на C#: когда ICommand действительно полезен, а когда хватает делегата или обычного сервисного метода.
Задача паттерна
Команда превращает действие в объект. Такой объект можно:
- передавать между слоями;
- класть в очередь;
- логировать;
- повторять и отменять.
Клиент вызывает команду через общий интерфейс и не знает детали выполнения.
Классический вариант
public interface ICommand
{
void Execute();
void Undo();
}
public class SaveDocumentCommand : ICommand
{
private readonly DocumentService _receiver;
private readonly string _path;
public SaveDocumentCommand(DocumentService receiver, string path)
{
_receiver = receiver;
_path = path;
}
public void Execute() => _receiver.Save(_path);
public void Undo() => _receiver.RestorePreviousVersion(_path);
}
ToolbarButton (invoker) хранит ICommand и вызывает Execute(). Такая форма удобна в UI, редакторах и workflow-системах.
Что даёт C# поверх канона
Для простых сценариев можно хранить команды как делегаты:
var actions = new Dictionary<string, Action>
{
["refresh"] = () => cache.Reload(),
["clear"] = () => cache.Clear()
};
actions["refresh"]();
Минимум кода, но нет явной модели Undo, метаданных команды и сериализации.
Если нужен контекст действия, версия, user id, idempotency key, объект команды оказывается удобнее:
public record CreateOrderCommand(Guid UserId, IReadOnlyList<OrderItemDto> Items);
Command и MediatR в .NET
В современных ASP.NET Core проектах паттерн Command часто проявляется через MediatR:
CreateOrderCommand : IRequest<Guid>— объект намерения;CreateOrderCommandHandler— исполнитель;ISender.Send(command)— invoker.
Это вариант паттерна, адаптированный под DI и pipeline-поведения (валидация, логирование, трейсинг). Детально — в MediatR и pipeline.
Когда Command уместен
| Ситуация | Почему помогает Command |
|---|---|
| Undo/redo в UI | Команда хранит данные для отката |
| Очереди и отложенное исполнение | Объект можно сериализовать и выполнить позже |
| Аудит действий | Один объект = одна бизнес-операция с метаданными |
| CQRS в Application-слое | Явное разделение сценариев записи и чтения |
Когда это лишний слой
Если операция:
- короткая;
- не требует очереди, истории и отката;
- вызывается в одном месте;
обычный сервисный метод обычно проще:
await orderService.CreateAsync(dto, ct);
Иногда ICommand + Handler + Invoker только увеличивают число файлов без новой ценности.
Чек-лист
| Вопрос | Рекомендация |
|---|---|
| Нужно отменять и повторять действия | Command-объект |
| Нужны очередь, ретраи, журнал | Command-объект |
| Просто вызвать одну операцию | Сервисный метод или Action |
| Есть Application-слой с MediatR | Команды как IRequest |
В C# Command хорошо работает как контракт бизнес-действий и транспорт операции через слои. Для локальных коротких вызовов проще и дешевле остаются обычные методы.
Итог
Паттерн Command остаётся актуальным, когда действие нужно трактовать как отдельную сущность системы. В .NET это часто реализуется через MediatR, очереди и pipeline. Для простых вызовов разумнее оставить плоский сервисный API.
См. также
См. также
Другие статьи этого же раздела в боковом меню (как на странице "О разделе"). Паттерн — это повторяющийся шаблон, узор или схема. Паттерны встречаются повсюду — в природе, архитектуре, поведении людей и, конечно, в программировании. Порождающие паттерны проектирования — это группа шаблонов, направленных на решение задач, связанных с созданием объектов. Структурные паттерны — это группа шаблонов проектирования, решающих задачи организации классов и объектов таким образом, чтобы обеспечить гибкую архитектуру программного обеспечения. Поведенческие паттерны — это группа шаблонов проектирования, которые определяют способы взаимодействия объектов и распределения ответственности между ними. Архитектурные паттерны — это проверенные решения для организации структуры программного обеспечения. Интеграция систем — одна из центральных задач в современной разработке программного обеспечения. Паттерны доменного моделирования представляют собой проверенные решения для организации бизнес-логики в программных системах. Паттерн Strategy в C# — классическая реализация через интерфейс, замена на Func и Action, DI и критерии выбора без лишних абстракций. Паттерн Iterator в C# — ручной IEnumerator, генерация итератора компилятором через yield return, ленивость, LINQ и случаи, когда класс писать всё же нужно. Abstract Factory в C# и .NET — классическая схема через интерфейсы, замена через DI-контейнер, фабричный делегат и keyed services в .NET 8. Паттерн Observer в C# — event и делегаты, IObservable IObserver, слабая связанность, отписка и как не поймать утечки памяти в долгоживущих сервисах.Обзор паттернов проектирования
Порождающие паттерны
Структурные паттерны
Поведенческие паттерны
Архитектурные паттерны
Паттерны интеграции внешних систем
Паттерны проектирования доменных моделей
Стратегия в C#
Итератор в C#
Фабрика в C#
Наблюдатель в C#