Let’s refactor further the previous code sample using the composite pattern.
See the link(https://www.dofactory.com/net/composite-design-pattern) for the details of what is a composite pattern.
Let’s bring back the last code here.
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(); }
In the previous sample, all individual commands executed by comparing the command name. However, we had to manually compare the string “all” in the if-else statement.
By implementing the composite pattern, we can remove if-else entirely as below. Instead, we can create an AllCommands object, which is an implementation of ICommand. and add that group of command objects (allCommands) into the availableCommands variable.
var availableCommands = new List<ICommand> { new UpdatePrice(_stockPriceManager, stocksToRead, _appSettings.DaysToReadFromWeb), new UpdateStats(_stockPriceManager, stocksToAnalyze), new SimulateCommand(_stockPriceManager, stocksToAnalyze, _marketWatchRepository, investDay, _tradeOption, _logger, _appSettings) }; var allCommands = new AllCommands() { commands = availableCommands }; availableCommands.Add(allCommands); var command = availableCommands.Single(c => c.Name == commandName); await command.Execute();
The key concept is making a group of individual commands as the same interface to the individual command so as to treat a group of commands as a command. Potentially, we can add a group of the group easily using this composite pattern otherwise the original if-else code could have been very messy.
The AllCommands class looks like below. As explained, the key is having a list of ICommand inside of ICommand implementation.
public class AllCommands : ICommand { public List<ICommand> commands { get; set; } public string Name => "All"; public Task Execute() { commands.ForEach(async c => await c.Execute()); return Task.CompletedTask; } }