In this post I would like to present a simple backend system based on the Command Design Pattern where each command has own independent scope. While designing a quite complicated system with many different functions – I tried to come up with an elegant solution. The main goal was to encapsulate different logic and avoid expensive spaghetti code, which is difficult to maintain. The following solution is worked very well on my last project, so I decided to write this post. The below example is simplified – I am focusing on the idea only. Maybe in future posts, I will extend this simple scenario.
Our heroid cast consists of:
- CommandBase (Command) – declares an interface for executing an operation
- ConcreteCommand (ImportCommand, NotificationCommand) – defines a binding between a Receiver object and an action. Implements Execute by invoking the corresponding operation(s) on Receiver
- Client (MainApp) – creates a ConcreteCommand object and sets its receiver
- CommandInvoker – execute the commands (Processor)
- ReceiverBase – base code for concrete receivers, setting some parameters
- ConcreteReceiver – implements custom logic (ImportReceiver, CommandReceiver)
CommandBase
public abstract class CommandBase { protected readonly ReceiverBase Receiver; public CommandBase(ReceiverBase receiver) { Receiver = receiver; } public abstract void Execute(); }
ImportCommand
public class ImportCommand : CommandBase { public ImportCommand(ReceiverBase receiver) : base(receiver) { } public override void Execute() { Console.ForegroundColor = ConsoleColor.Green; var importReceiver = Receiver as ImportReceiver; if (importReceiver == null) throw new ArgumentNullException("Import Receiver is null !"); importReceiver.ProceesImport(); } }
NotificationCommand
public class NotificationCommand : CommandBase { public NotificationCommand(ReceiverBase receiver) : base(receiver) { } public override void Execute() { Console.ForegroundColor = ConsoleColor.Cyan; var notificationReceiver = Receiver as NotificationReceiver; if (notificationReceiver == null) throw new ArgumentNullException("Notification Receiver is null !"); notificationReceiver.SendNotifications(); } }
ReceiverBase
public abstract class ReceiverBase { protected IDataContextFactory DataContextFactory; protected object[] Parameters; public ReceiverBase(IDataContextFactory dataContextFactory, params object[] parameters) { DataContextFactory = dataContextFactory; Parameters = parameters; } }
ImportReceiver
public class ImportReceiver : ReceiverBase { public ImportReceiver(IDataContextFactory dataContextFactory, params object[] parameters) : base(dataContextFactory, parameters) { } public void ProceesImport() { using (IUnitOfWork unitOfWorkDataContext = DataContextFactory.GetNewDataContext()) { StartImport(); FinishImport(); unitOfWorkDataContext.Commit(); } } private void StartImport() { Console.WriteLine(" ImportReceiver: StartImport() "); } private void FinishImport() { Console.WriteLine(" ImportReceiver: EndImport()"); } }
NotificationReceiver
public class NotificationReceiver : ReceiverBase { public NotificationReceiver(IDataContextFactory dataContextFactory, params object[] parameters) : base(dataContextFactory, parameters) { } public void SendNotifications() { using (IUnitOfWork unitOfWorkDataContext = DataContextFactory.GetNewDataContext()) { SendSMS(); SendEmails(); unitOfWorkDataContext.Commit(); } } private void SendEmails() { Console.WriteLine(" NotificationReceiver: SendSMS()"); } private void SendSMS() { Console.WriteLine(" NotificationReceiver: SendEmails()"); } }
CommandInvoker
public class CommandInvoker { public void SetCommand(CommandBase command) { _commands.Add(command); } public void ExecuteCommands() { foreach (var command in _commands) { command.Execute(); } } }
Now we are ready to go, so let’s put code together and do some serious damage!
static void Main(string[] args) { Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine("\n Command service Start"); IDataContextFactory dataContextFactory = new DataContextFactory(); var importCommand = new ImportCommand(new ImportReceiver(dataContextFactory)); var notificationCommand = new NotificationCommand(new NotificationReceiver(dataContextFactory)); var commandInvoker = new CommandInvoker(); /* Hook up the commands */ commandInvoker.SetCommand(importCommand); commandInvoker.SetCommand(notificationCommand); commandInvoker.ExecuteCommands(); Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine(" Job done"); Console.WriteLine(" Command service Stop"); Console.ReadKey(); }
As we see program works well, feel free to extend and customize it to fit your needs. Source code is avaliable here