Pages

Thursday, December 10, 2009

Command Pattern Revisited

Command Pattern:


Recently i looked at the command pattern from the Gof book and decided that I'll use it but as it turned out the base implementation didn't fit my needs, so i had to create my own, and share the implementation here.

A standard command pattern takes as a base the object receiver(s) that it will be working on and the invoker as some Manager class or something that fits the design, and then the base command class has concrete command subclasses that do specific thing on the receiver class.

Heres mine:




So what's new?

The interfaces and the concrete command classes. We set a most basic interface IBaseCommandalble to serve as our most basic command able object, then other interfaces inherit from it in case we wanted to have different types of receivers with different methods.

So wheres the gain?

well in standard implementation at some point we had to do this for e.g
Receiver receiver = new Receiver();
Command command = new ConcreteCommand(receiver);


this is just a concept but at some point we had to create a concrete command and add the receiver in the constructor property whatever. Now thanks to generics we don't not even in the base command class.

so it goes down to this:

Command command = new InvokerCommand<MyClass>();
command.Execute();


This can seam as a simple cosmetic issue but I'm sure you will find lots of benefits here.

So lets see some of the code:

/// <summary>
/// The Simple Invoker class.
/// </summary>
public class Invoker
{
private Command command;

public void SetCommand(Command command)
{
this.command = command;
}

public void ExecuteCommand
(params object[] parameters)
{
command.Execute(parameters);
}
}

/// <summary>
/// The IBaseCommandable interface.
/// Defines the base interface for concrete Commandable
/// interfaces,
/// and therefore shouldn't be modified.
/// </summary>
public interface IBaseCommandable
{ }

/// <summary>
/// The IExecutionCommandable interface. 
/// Defines execution operations with string.
/// </summary>
public interface IExecutionCommandable
: IBaseCommandable
{
void StartExecution(string name);
void StopExecution(string name);
}

/// <summary>
/// The IExecutionCommandable interface.
/// Defines void non parametric operations.
/// </summary>
public interface IVoidCommandable
: IBaseCommandable
{
void Execute();
}

/// <summary>
/// The Command class.
/// </summary>
public abstract class Command
{
protected IBaseCommandable commandableObject;

public Command(IBaseCommandable commandableObject)
{
this.commandableObject = commandableObject;
}

public abstract void Execute
(params object[] parameters);
}

/*
     * The new() constraint produes Activator.CreateInstance(),
     * but there is a workaroud, and I didnt had the time to
     * do it, sorry.
     */

/// <summary>
/// The Invoke Command class.
/// </summary>
public class InvokeCommand<T> : Command
where T : IExecutionCommandable, new()
{
/*
         * The most interesting things are here,
         * we just create a new generic object and pass it
         * to the base class,
         * so no need to pass it in the class.
         */

/// <summary>
/// Initializes a new instance of the
/// <see cref="InvokeCommand&lt;T&gt;"/> class.
/// </summary>
public InvokeCommand()
: base(new T())
{
}

/// <summary>
/// Executes the command.
/// </summary>
/// <param name="name">The name.</param>
public override void Execute
(params object[] parameters)
{
((IExecutionCommandable)commandableObject).
StartExecution(parameters[0].ToString());
}
}


Ok so as you see the code is very simple, the only thing that's left to tune up is the new() there is a workaround by creating a delegate class, and it works, but I haven't tried it myself.

The other thing is the annoying params object[] on the command Execute, I tried to do it some other way (Lambdas) but due the lack of time I left it like so, but I'm sure it can be done better.

That is all.

Thanks for reading ;)

No comments:

 
ranktrackr.net