What is the problem we are trying to solve?
Look at the example blow
using System;
namespace CommandPatternTutorial
{
internal class Program
{
private static void Main(string[] args)
{
var commandExecutor = new CommandExecutor();
commandExecutor.ProcessOrders("Update");
}
}
public class CommandExecutor
{
public void ProcessOrders(String commandName)
{
switch (commandName)
{
case "Insert":
Insert();
break;
case "Update":
Update();
break;
case "Delete":
Delete();
break;
default:
Console.WriteLine("Command not found");
break;
}
}
public void Insert()
{
Console.WriteLine("Insert Order");
}
public void Update()
{
Console.WriteLine("Update Order");
}
public void Delete()
{
Console.WriteLine("Delete Order");
}
}
}
If you need to add a new command in there, you would have to modify the CommandExecutor class. This violates the
Solid Open-Closed and the single responsibility design principles. To avoid these violations we will apply the Command and
factory patterns.
Command Pattern
The complete code is given below. The crux of the command pattern is the ICommand interface which has just the Execute method. So command pattern in itself is very simple, simultaneous application of factory pattern is what makes it a bit more harder to understand.
Program.cs
using CommandPatternTutorial.Interfaces;
namespace CommandPatternTutorial
{
internal class Program
{
private static void Main(string[] args)
{
string commandName = "UpdateCommand";
var commandFactory = new CommandFactory();
ICommand command = commandFactory.GetCommand(commandName);
command.Execute();
}
}
}
ICommand.cs
namespace CommandPatternTutorial.Interfaces
{
public interface ICommand
{
void Execute();
}
}
ICommandFactory.cs
using CommandPatternTutorial.Interfaces;
namespace CommandPatternTutorial
{
public interface ICommandFactory
{
ICommand GetCommand(string commandName);
}
}
CommandFactory.cs
using System;
using System.Collections.Generic;
using System.Reflection;
using CommandPatternTutorial.Commands;
using CommandPatternTutorial.Interfaces;
namespace CommandPatternTutorial
{
internal class CommandFactory : ICommandFactory
{
private Dictionary<string, Type> _commandsDictionary;
public CommandFactory()
{
LoadCommands();
}
public ICommand GetCommand(string commandName)
{
commandName =
commandName.ToLower();
ICommand command;
if (_commandsDictionary.ContainsKey(commandName))
{
Type type = _commandsDictionary[commandName];
if (type != null)
{
command = (ICommand) Activator.CreateInstance(type);
}
else
{
command = new NullCommand();
}
}
else
{
command = new NullCommand();
}
return command;
}
private void LoadCommands()
{
_commandsDictionary = new Dictionary<string, Type>();
//Get
the interfaces and classes in the current assembly
Type[] typesinCurrentAssembly = Assembly.GetExecutingAssembly().GetTypes();
string interfaceName = typeof (ICommand).ToString(); //"ICommand"
foreach (Type type in typesinCurrentAssembly)
{
//Find
the types that implement ICommand and add it to the dictionary _commandsDictionary
if (type.GetInterface(interfaceName) != null)
{
string typeName =
type.Name.ToLower();
_commandsDictionary.Add(typeName, type);
}
}
}
}
}
UpdateCommand.cs
using System;
using CommandPatternTutorial.Interfaces;
namespace CommandPatternTutorial.Commands
{
internal class UpdateCommand : ICommand
{
public void Execute()
{
Console.WriteLine("Update
Order");
}
}
}
NullCommand.cs
using System;
using CommandPatternTutorial.Interfaces;
namespace CommandPatternTutorial.Commands
{
internal class NullCommand : ICommand
{
public void Execute()
{
Console.WriteLine("Command Not
Found");
}
}
}
Now if you need to add a new command, all you need to do is write a class that implements ICommand interface.