Command pattern
Sometimes, you don’t want to do execute your functions immediately.You can use the Command pattern to add work to a queue, to be done later. You can use it to retry, if a command cannot execute properly. You might be able to use this to add “undo” capabilities to a program.
Invoker – the object that executes commands by calling execute() on the object passed to it.
Command – interface that defines the operations that must support each command (to perform tasks, rollbacks etc.).
Concrete command – class providing implementation of the interface command, focusing on serving a single task.
Reciever – receives the results of the command action
Example
Our example will be a program consisting of a trainer who gives command to sportsmans.
Let’s write an interface to our commands.It has two methods execute() and undo()
// Command public interface ICommand { void Execute(); void Undo(); }
And our concrete commands.
Running:
// ConcreteCommand public class Running : ICommand { public Sportsperson player { get; set; } public Running(Sportsperson _player) { player = _player; } public void Execute() { Console.WriteLine("{0} runs\n", player.name); } public void Undo() { Console.WriteLine("{0} - remove runs from your training plan\n", player.name); } }
Jumping:
// ConcreteCommand public class Jumping : ICommand { public Sportsperson player { get; set; } public Jumping(Sportsperson _player) { player = _player; } public void Execute() { Console.WriteLine("{0} jumps\n", player.name); } public void Undo() { Console.WriteLine("{0} - remove jumping from your training plan\n", player.name); } }
And workout at the gym:
// ConcreteCommand public class Gym : ICommand { public Sportsperson player { get; set; } public Gym(Sportsperson _player) { player = _player; } public void Execute() { Console.WriteLine("{0} lifts weights at the gym\n", player.name); } public void Undo() { Console.WriteLine("{0} - remove lifts weights at the gym from your training plan\n", player.name); } }
Our reciver is sportsperson, issued commands will affect on him.
// Receiver public class Sportsperson { public string name { get; set; } public Sportsperson(string _name) { name = _name; } }
Class Trener is the invoker. Adds specific commands and then execute operations on them in the order they were added and can also remove some training.
// Invoker public class Trener { private readonly List<ICommand> traning = new List<ICommand>(); public void AddTraning(ICommand _traning) { traning.Add(_traning); } public void Train() { // Apply traning in the order they were added. foreach (ICommand train in traning) { train.Execute(); } } public void RemoveTrain(int index) { var train = traning[index]; train.Undo(); traning.Remove(train); } }
Let’s see how it’s works.
Trainer will work out a training plan for the two sportsmans and then tells them to do it. And next he removing the specific training, in this case workout at the gym.
static void Main(string[] args) { Trener enduranceTraning = new Trener(); Trener strengthTraining = new Trener(); Sportsperson sabina = new Sportsperson("Sabina"); Sportsperson pawel = new Sportsperson("Pawel"); WriteDiffrentColor("'Sabina' traning"); enduranceTraning.AddTraning(new Running(sabina)); enduranceTraning.AddTraning(new Jumping(sabina)); enduranceTraning.AddTraning(new Gym(sabina)); enduranceTraning.Train(); WriteDiffrentColor("'Pawel' traning"); strengthTraining.AddTraning(new Gym(pawel)); strengthTraining.AddTraning(new Running(pawel)); strengthTraining.Train(); WriteDiffrentColor("Remove the gym from a training plan 'Sabina'"); enduranceTraning.RemoveTrain(2); enduranceTraning.Train(); WriteDiffrentColor("Remove the gym from a training plan 'Pawel'"); strengthTraining.RemoveTrain(0); strengthTraining.Train(); Console.ReadKey(); } static void WriteDiffrentColor(string value) { Console.ForegroundColor = ConsoleColor.DarkGreen; Console.WriteLine(value.PadRight(Console.WindowWidth - 1)); Console.ResetColor(); }
Summary
If we add to this pattern – dependency injection. We get nicely composed applications eg. CQRS.
Link to the projekt HERE
Kiedyś oparłem na tym wzorcu backend swojej solucji – wyszło mega. Zarys rozwiązania wrzuciłem tutaj:
http://piotrluksza.com/2014/10/16/simple-backend-solution-based-on-command-pattern/
Pozdrawiam pl