Translate

Monday, May 18, 2015

Command Pattern Tutorial C# (Also known as Action or Transaction Pattern)

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.

No comments:

Post a Comment

Comments will appear once they have been approved by the moderator