A command encapsulates a unit of work. Typically, a command might insert/update a database record, send an email or just update a model. There are numerous ways one can model a command. In this post I describe a simple command mechanism that is suitable for standalone applications. I will also discuss the pros and cons of the approach.
Top
In this post...
TopCreating The Project
The project is a Console Application, using the .NET Framework (Ver 4.8). The project is named, CommandApp.
No external libraries are required for this project.
TopExtension/Helper methods
To help visualise program flow I add an extension class.
using System;
namespace CommandApp
{
public static class Extensions
{
//The Trace extension allows one to simply output a value to the console.
//The method is easily modified to send output elsewhere..
public static void Trace<T>(this T src) =>
Console.WriteLine(src);
}
}
Top
Simple Commands
The simple command encapsulates command values. The command is also responsible for its own behaviour, in this case, executing command code. The command is executed synchronously, that is, on the thread that created the command. The following diagram illustrates the concept.
The client is simply code that creates and executes the command. The code for the simple command is as follows...
Topusing System;
namespace CommandApp.SimpleCommands
{
public abstract class Command
{
protected Command() { }
public bool IsSuccess => null == Exception;
public Exception Exception { get; private set; }
public void Execute()
{
try
{
OnExecute();
}
catch (Exception e)
{
this.Exception = e;
}
}
public abstract void OnExecute();
}
}
Top
Code Walkthrough
- The class is declared as abstract, concrete classes override/implement onExecute to implement the command.
- Client(s) create a new command instance then call the Execute method which catches any exceptions and places into to the Exception property.
- Client(s) can query the command to check for success or failure an act appropriately.
Simple command Pros and Cons
Pros
- Simple to use.
- No infrastructure required.
- Command code, that is values and behaviour all in a single class.
- Works when using the Command base class that refers to a concraete instance. Can thank Polymorphism for this. For example, Command myCmd = new MyCommand()
Cons
- Command is blocking - main thread blocks whilst waiting for command execution.
- Including cross-cutting concerns is difficult unless such concerns are included in the Execute parameters. However, this will complicate calling the Execute method.
- Client(s) can create and execute a given command. Not necessarily bad, but it might be best to separate command creation from command execution. This would allow the software to "inject" code before and after executing code.
Sample Simple Command
The following code illustrates using the simple class. The example Sleeps for 1000ms to simulate a time consuming command.
using System.Threading;
namespace CommandApp.SimpleCommands
{
public class AddCustomerCommand : Command
{
private readonly string _firstName;
private readonly string _lastName;
public int Id { get; private set; }
public AddCustomerCommand(string firstName, string lastName)
{
_firstName = firstName;
_lastName = lastName;
}
public override void OnExecute()
{
"---------------------------------------------------".Trace();
$"AddCustomerCommand({_firstName}, {_lastName})".Trace();
"About to sleep for 1000ms to simulate a time consuming command".Trace();
Thread.Sleep(1000);
"Setting Id to 1 to simulate adding a new database record and returning a new Id".Trace();
Id = 1;
"completed".Trace();
}
}
}
Top
Testing The simple Command
The following code was used to test the simple command...
namespace CommandApp.SimpleCommands
{
public static class Test
{
public static void Run()
{
AddCustomerCommand cmd = new AddCustomerCommand("Fred", "Bloggs");
cmd.Execute();
}
}
}
If all goes well, you should see the following text on the command prompt...
Top
No comments:
Post a Comment