Паттерн Команда инкапсулирует запрос в виде объекта, делая возможной параметризацию клиентских объектов с другими запросами, организацию очереди или регистрацию запросов, а также поддержку отмены операций.
Паттерн Команда отделяет объект, выдающий запросы, от объекта, который умеет эти запросы выполнять. Объект команды инкапсулирует получателя с операцией или набором операций.
Инициатор вызываем метод Execute() объекта команды что приводит к выполнению соответствующих операций с получателем. Паттерн команды могут поддерживать механизмы отмены, восстанавливающий объект в состоянии до последнего вызова метода Execute();
Макрокоманды— простое расширение паттерна Команда, позволяющее выполнять цепочки из нескольких команд, в них так же легко реализуется механизм отмены.
Команды также могут использоваться для реализации система регистрации команд и поддержки транзакций.
В данном примере рассмотрим две вариации паттерна, первый пример будет без возможности механизма отмены, другой с отменой, сделал так специально что бы было проще разобраться в паттерне.
Пример 1 представим мы разрабатываем систему умный дом, у нас есть ТЗ которая подразумевает управление освещением в доме. Я не стал усложнять пример, отдельно взятой комнате, будем включать и выключать освещение во всем доме)
using System; namespace Паттерн_Команда { /// <summary> /// Единственный интерфейс с 2 методами /// </summary> public interface Command { void Execute(); void Undo(); } public class LightCommand : Command { Light light; public LightCommand(Light light) => this.light = light; public void Execute() => light.On(); public void Undo() => light.Off(); } /// <summary> /// Класс управляет набором объектов команд, при нажамии одной из кнопок активизируем методы Execute Undo /// Сам класс ничего не знает о тех классах, к которым он обращается, так как он отделен от них объектом команды /// </summary> public class SimpleRemoteControl { Command slot; public SimpleRemoteControl() { } public void SetCommand(Command command) => slot = command; public void ButtonOn() => slot.Execute(); public void ButtonOff() => slot.Undo(); } public class Light { public Light(){} public void Off() => Console.WriteLine("Выключили свет"); public void On() => Console.WriteLine("Включили свет"); } class Program { static void Main(string[] args) { SimpleRemoteControl remote = new SimpleRemoteControl(); LightCommand lightCommand = new LightCommand(new Light()); remote.SetCommand(lightCommand); remote.ButtonOn(); remote.ButtonOff(); Console.ReadKey(); } } }

Пример 2 основан на механизме отмены, будем так же оборудовать наш умный дом новой функцией управления вентилятором. У нас будет несколько режимов, а так же возможность возврата предыдущего режима.
using System; using System.Collections.Generic; namespace Паттерн_Команда { ///// <summary> ///// Единственный интерфейс с 2 методами ///// </summary> public interface Command { void Execute(); void Undo(); } public enum Mode { High = 3, Medium = 2, Low = 1, Off = 0, } public class CeilingFan { Mode speed; string location; public CeilingFan(string location) { this.location = location; speed = Mode.Off; } public void High() { speed = Mode.High; } public void Medium() { speed = Mode.Medium; } public void Low() { speed = Mode.Low; } public void Off() { speed = Mode.Off; } public Mode GetSpeed() { return speed; } } internal class CeilingFanOffCommand : Command { private CeilingFan ceilingFan; Mode prevSpeed; public CeilingFanOffCommand(CeilingFan ceilingFan) { this.ceilingFan = ceilingFan; } public void Execute() { prevSpeed = ceilingFan.GetSpeed(); ceilingFan.Off(); Console.WriteLine("Режим выключения"); } public void Undo() { switch (prevSpeed) { case Mode.High: ceilingFan.High(); break; case Mode.Medium: ceilingFan.Medium(); break; case Mode.Low: ceilingFan.Low(); break; case Mode.Off: ceilingFan.Off(); break; } Console.WriteLine("Возобновили режим выключения"); } } internal class CeilingFanMediumCommand : Command { private CeilingFan ceilingFan; Mode prevSpeed; public CeilingFanMediumCommand(CeilingFan ceilingFan) { this.ceilingFan = ceilingFan; } public void Execute() { prevSpeed = ceilingFan.GetSpeed(); ceilingFan.Medium(); Console.WriteLine("Режим средней мощности"); } public void Undo() { switch (prevSpeed) { case Mode.High: ceilingFan.High(); break; case Mode.Medium: ceilingFan.Medium(); break; case Mode.Low: ceilingFan.Low(); break; case Mode.Off: ceilingFan.Off(); break; } Console.WriteLine("Возобновили режим средней мощности"); } } public class CeilingFanHighCommand : Command { CeilingFan ceilingFan; Mode prevSpeed; public CeilingFanHighCommand(CeilingFan ceilingFan) { this.ceilingFan = ceilingFan; } public void Execute() { prevSpeed = ceilingFan.GetSpeed(); ceilingFan.High(); } public void Undo() { switch (prevSpeed) { case Mode.High: ceilingFan.High(); break; case Mode.Medium: ceilingFan.Medium(); break; case Mode.Low: ceilingFan.Low(); break; case Mode.Off: ceilingFan.Off(); break; } Console.WriteLine("Режим максимальной мощности"); } } ///// <summary> ///// Класс управляет набором объектов команд, при нажамии одной из кнопок активизируем методы Execute UnExecute ///// Сам класс ничего не знает о тех классах, к которым он обращается, так как он отделен от них объектом команды ///// </summary> public class SimpleRemoteControl { List<Command> onCommands; List<Command> offCommands; Command undoCommand; public SimpleRemoteControl() { onCommands = new List<Command>{null,null,null,null,null,null}; offCommands = new List<Command> { null, null, null, null, null, null }; } public void SetCommand(int slot, Command command, Command offComand) { onCommands[slot] = command; offCommands[slot] = offComand; } public void ButtonOn(int slot) { onCommands[slot].Execute(); undoCommand = onCommands[slot]; Console.WriteLine("Включили вентелятор"); } public void ButtonOff(int slot) { offCommands[slot].Execute(); undoCommand = offCommands[slot]; Console.WriteLine("Выключили вентелятор"); } internal void ButtonUndo() { undoCommand.Undo(); Console.WriteLine("Возврат предыдущего режима"); } } class Program { static void Main(string[] args) { SimpleRemoteControl remoteControl = new SimpleRemoteControl(); CeilingFan ceilingFan = new CeilingFan("Спальня"); CeilingFanMediumCommand ceilingFanMedium = new CeilingFanMediumCommand(ceilingFan); CeilingFanHighCommand ceilingFanHigh = new CeilingFanHighCommand(ceilingFan); //создаем экземпляры 3 команды высокой, средней и для выключения CeilingFanOffCommand ceilingFanOff = new CeilingFanOffCommand(ceilingFan); remoteControl.SetCommand(0, ceilingFanMedium, ceilingFanOff); remoteControl.SetCommand(1, ceilingFanHigh, ceilingFanOff); remoteControl.ButtonOn(0); remoteControl.ButtonOff(0); remoteControl.ButtonUndo(); remoteControl.ButtonOn(1); remoteControl.ButtonUndo(); Console.ReadKey(); } } }
