Design Patterns - Command

Command Pattern Characteristics

  • Command
    • Holds the instructions and references to things that it needs in order for it to be executed
  • Receiver
    • Command will execute Receiver
  • Invoker
    • Invoker will execute Command, and will also keep track of all executed commands
  • Client
    • Client decides which command to schedule for execution

A command contains all the data to process the request now or at a later time. This means we could execute the command right away once the client schedule that command, or we could schedule all the commands to be executed later on in the lifetime of our application.

Example: AddToCartCommand

  • The product which should be added to the cart
  • The shopping cart
  • A way to check stock availability

ICommand Interface

Because we may need to implement different command, we should create a ICommand interface.

It contains three methods. Execute() will execute the command. CanExecute() will check if a command can be execute of not. Undo() will undo all commands we executed before (using a Stack to maintain all executed commands)

1
2
3
4
5
6
public interface ICommand
{
void Execute();
bool CanExecute();
void Undo();
}

Next we need to implement CommandManager, which is the Invoker component. It contains a Stack Data Structure to maintain the Commands list. When the Client (UI Button) adds a command to the CommandManager, it will be added to the list. (We can also add extra feature like introduce a delay of executing commands or redo all commands later).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class CommandManager
{
private Stack<ICommand> commands = new Stack<ICommand>();

public void Invoke(ICommand command)
{
if (command.CanExecute())
{
commands.Push(command);
command.Execute();
}
}

public void Undo()
{
while (commands.Count > 0)
{
var command = commands.Pop();
command.Undo();
}
}
}

Next we start to implement a command AddToCartCommand

1
public class AddToCartCommand : ICommand

It takes a shoppingCartRepository object, a productRepository object and a product

1
2
3
4
5
6
7
8
public AddToCartCommand(IShoppingCartRepository shoppingCartRepository,
IProductRepository productRepository,
Product product)
{
this.shoppingCartRepository = shoppingCartRepository;
this.productRepository = productRepository;
this.product = product;
}

Just a reminder, the Repository is a pattern for abstracting data access. We could have access the data store from a SQL DB, a web service or a CSV file, but our application doesn’t need to know that.

In our case, the shoppingCartRepository and the productRepository are both just a local Dictionary data structure.

1
2
3
4
5
6
public bool CanExecute()
{
if (product == null) return false;

return productRepository.GetStockFor(product.ArticleId) > 0;
}

CanExecute() will check if our productRepository actually has the required product.

1
2
3
4
5
6
7
8
public void Execute()
{
if (product == null) return;

productRepository.DecreaseStockBy(product.ArticleId, 1);

shoppingCartRepository.Add(product);
}

Execute() will decrease the product quantity by one and add it to shoppingCartRepository

1
2
3
4
5
6
7
8
9
10
public void Undo()
{
if (product == null) return;

var lineItem = shoppingCartRepository.Get(product.ArticleId);

productRepository.IncreaseStockBy(product.ArticleId, lineItem.Quantity);

shoppingCartRepository.RemoveAll(product.ArticleId);
}

Undo() will put the product from shoppingCartRepository back to the productRepository

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var shoppingCartRepository = new ShoppingCartRepository();
var productsRepository = new ProductsRepository();

var product = productsRepository.FindBy("SM7B");

var addToCartCommand = new AddToCartCommand(shoppingCartRepository,
productsRepository,
product);

var increaseQuantityCommand = new ChangeQuantityCommand(
ChangeQuantityCommand.Operation.Increase,
shoppingCartRepository,
productsRepository,
product);

var manager = new CommandManager();
manager.Invoke(addToCartCommand);
manager.Invoke(increaseQuantityCommand);
manager.Invoke(increaseQuantityCommand);
manager.Invoke(increaseQuantityCommand);
manager.Invoke(increaseQuantityCommand);

Finally we just need to compose all the necessary objects on app starts. And add the commands to CommandManager.

Command Pattern in WPF

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public interface ICommand
{
//
// Summary:
// Occurs when changes occur that affect whether or not the command should execute.
event EventHandler CanExecuteChanged;

//
// Summary:
// Defines the method that determines whether the command can execute in its current
// state.
//
// Parameters:
// parameter:
// Data used by the command. If the command does not require data to be passed,
// this object can be set to null.
//
// Returns:
// true if this command can be executed; otherwise, false.
bool CanExecute(object parameter);
//
// Summary:
// Defines the method to be called when the command is invoked.
//
// Parameters:
// parameter:
// Data used by the command. If the command does not require data to be passed,
// this object can be set to null.
void Execute(object parameter);
}

WPF application has built in ICommand interface. If we want to use our Command implementation (RemoveAllFromCartCommand) with this ICommand interface. We could bind the method with a UI button, then create a RelayCommand Class, which will invoke RemoveAllFromCartCommand method.

  • UI Button ->(bind)-> ICommand method ->(invoke)-> RelayCommand ->(invoke)-> RemoveAllFromCartCommand
1
<Button Margin="0 5 5 0" Command="{Binding RemoveAllFromCartCommand}">Clear</Button>
1
public System.Windows.Input.ICommand RemoveAllFromCartCommand { get; private set; }
1
2
3
4
5
6
7
8
9
RemoveAllFromCartCommand = new RelayCommand(
execute: () =>
{
removeAllFromCartCommand.Execute();

Refresh();
},
canExecute:() => removeAllFromCartCommand.CanExecute()
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class RelayCommand : System.Windows.Input.ICommand
{
private readonly Action execute;
private readonly Func<bool> canExecute;

public RelayCommand(Action execute, Func<bool> canExecute)
{
this.execute = execute;
this.canExecute = canExecute;
}

public bool CanExecute(object parameter)
{
return canExecute?.Invoke() ?? false;
}

public void Execute(object parameter)
{
execute?.Invoke();
}

public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}

public void RaiseCanExecuteChanged()
{
CommandManager.InvalidateRequerySuggested();
}
}

Summary

Command Pattern converts the request from Client to an object(ICommand). And the children implementation of the ICommand (AddToCartCommand) will take the Receiver as one of its input parameters (ShoppingCartRepository, ProductRepository). And it will implement the Execute() method, decide what should the Receiver do in Execute() method. And the Receiver should have all the needed information about the request(Product)