Design Pattern – Command

The command pattern is useful to handle direction from args in command line app. 

For example, there was an ugly code as below, which I wrote a while ago. As I simplified the code to focus on if-else statement, it may look not that bad.  But, I was struggling with managing the mapping each method with the command from argument especially when adding a new one or modifying the existing one. 

Many said there is code smell when you see a long if-else or case statement. I didn’t know what was the problem until I fixed it. 

                if (runOption == "all")
{
await _stockPriceManager.ReadStockPriceFromWeb(stocksToRead, _appSettings.DaysToReadFromWeb);

// Iterate simulation
var averageAnnualReturn = await IterateSimulationAsync(investDay, stocksToAnalyze, _tradeOption);

}
else if (runOption == "recalculate")
{
await _stockPriceManager.ReCalculateCoefficient(stocksToAnalyze);
}
else if (runOption == "simulate")
{
var averageAnnualReturn = await IterateSimulationAsync(investDay, stocksToAnalyze, _tradeOption);
}
else if (runOption.ToLower() == "readprice")
{
await _stockPriceManager.ReadStockPriceFromWeb(stocksToRead, _appSettings.DaysToReadFromWeb);
}

This code refactored as below using the command pattern. After refactoring, the selection condition was deligated to the concrete command object. To add a new action, it’s possible just to add new command object to the availablecommands array and no need to modify the code below that. Another and actually more important benefit that I didn’t show from this simple example code is that I could separate responsibility of each command under its own class. As you may imagine, most of those were inside the same class where if-else statement was. Implementing the command pattern naturally led me to implement the single responsibility principle. 

The downside of this approach is that you need to create a new 3 command class and one ICommand interface. When it’s a simple program like a prototype, we might want to just use a simple if-else style. But, if there is any chance the code become a long-running one, which implies that continuous add/modification will be followed by, I would use command pattern. 

                var availableCommands = new ICommand[]
{
new UpdatePrice(_stockPriceManager, stocksToRead, _appSettings.DaysToReadFromWeb),
new UpdateStats(_stockPriceManager, stocksToAnalyze),
new SimulateCommand(_stockPriceManager, stocksToAnalyze, _marketWatchRepository, investDay,
_tradeOption, _logger, _appSettings)
};

if (runOption == "all")
{
availableCommands.Select(async c => await c.Execute());
}
else
{
var command = availableCommands.Single(c => c.Name == runOption);
await command.Execute();
}

 

To see more about the command pattern, go to https://www.dofactory.com/net/command-design-pattern