Команда — это поведенческий паттерн, позволяющий заворачивать запросы или простые операции в отдельные объекты.
Это позволяет откладывать выполнение команд, выстраивать их в очереди, а также хранить историю и делать отмену.
Сложность:
Популярность:
Применимость: Паттерн можно часто встретить в C#-коде, особенно когда нужно откладывать выполнение команд, выстраивать их в очереди, а также хранить историю и делать отмену.
Признаки применения паттерна: Классы команд построены вокруг одного действия и имеют очень узкий контекст. Объекты команд часто подаются в обработчики событий элементов GUI. Практически любая реализация отмены использует принципа команд.
Концептуальный пример
Этот пример показывает структуру паттерна Команда , а именно — из каких классов он состоит, какие роли эти классы выполняют и как они взаимодействуют друг с другом.
Program.cs: Пример структуры паттерна
using System;
namespace RefactoringGuru.DesignPatterns.Command.Conceptual
{
// Интерфейс Команды объявляет метод для выполнения команд.
public interface ICommand
{
void Execute();
}
// Некоторые команды способны выполнять простые операции самостоятельно.
class SimpleCommand : ICommand
{
private string _payload = string.Empty;
public SimpleCommand(string payload)
{
this._payload = payload;
}
public void Execute()
{
Console.WriteLine($"SimpleCommand: See, I can do simple things like printing ({this._payload})");
}
}
// Но есть и команды, которые делегируют более сложные операции другим
// объектам, называемым «получателями».
class ComplexCommand : ICommand
{
private Receiver _receiver;
// Данные о контексте, необходимые для запуска методов получателя.
private string _a;
private string _b;
// Сложные команды могут принимать один или несколько объектов-
// получателей вместе с любыми данными о контексте через конструктор.
public ComplexCommand(Receiver receiver, string a, string b)
{
this._receiver = receiver;
this._a = a;
this._b = b;
}
// Команды могут делегировать выполнение любым методам получателя.
public void Execute()
{
Console.WriteLine("ComplexCommand: Complex stuff should be done by a receiver object.");
this._receiver.DoSomething(this._a);
this._receiver.DoSomethingElse(this._b);
}
}
// Классы Получателей содержат некую важную бизнес-логику. Они умеют
// выполнять все виды операций, связанных с выполнением запроса. Фактически,
// любой класс может выступать Получателем.
class Receiver
{
public void DoSomething(string a)
{
Console.WriteLine($"Receiver: Working on ({a}.)");
}
public void DoSomethingElse(string b)
{
Console.WriteLine($"Receiver: Also working on ({b}.)");
}
}
// Отправитель связан с одной или несколькими командами. Он отправляет
// запрос команде.
class Invoker
{
private ICommand _onStart;
private ICommand _onFinish;
// Инициализация команд
public void SetOnStart(ICommand command)
{
this._onStart = command;
}
public void SetOnFinish(ICommand command)
{
this._onFinish = command;
}
// Отправитель не зависит от классов конкретных команд и получателей.
// Отправитель передаёт запрос получателю косвенно, выполняя команду.
public void DoSomethingImportant()
{
Console.WriteLine("Invoker: Does anybody want something done before I begin?");
if (this._onStart is ICommand)
{
this._onStart.Execute();
}
Console.WriteLine("Invoker: ...doing something really important...");
Console.WriteLine("Invoker: Does anybody want something done after I finish?");
if (this._onFinish is ICommand)
{
this._onFinish.Execute();
}
}
}
class Program
{
static void Main(string[] args)
{
// Клиентский код может параметризовать отправителя любыми
// командами.
Invoker invoker = new Invoker();
invoker.SetOnStart(new SimpleCommand("Say Hi!"));
Receiver receiver = new Receiver();
invoker.SetOnFinish(new ComplexCommand(receiver, "Send email", "Save report"));
invoker.DoSomethingImportant();
}
}
}
Output.txt: Результат выполнения
Invoker: Does anybody want something done before I begin?
SimpleCommand: See, I can do simple things like printing (Say Hi!)
Invoker: ...doing something really important...
Invoker: Does anybody want something done after I finish?
ComplexCommand: Complex stuff should be done by a receiver object.
Receiver: Working on (Send email.)
Receiver: Also working on (Save report.)
Команда на других языках программирования