Practical C# API example with Command and Abstract factory patterns — Part 2
In the previous part, we implemented statistical functions via Command pattern techniques. In this part, we will implement the Abstract factory.
Previous part
Task recapitulation
Create REST API in C# that would receive JSON message with parameters method and data (message example is below this block). Parameter method represents statistical function as average (avg), variance (var) or standard deviation (std). API applies the selected method to the second parameter data (array of numbers).
{
"method": "avg",
"data": [1.0, 2.7, 5.4, 3.3, 9.1]
}
Abstract factory
Let’s think about task specification and how to solve the next part. A method in the API controller (we will implement it later) receives parameters function name and number array. So, we need to use an effective approach to select the correct statistical function (one of the Command classes) by the function name.
Of course, the quickest way is to implement the switch block directly into the controller method. When we create a new Command class, we will just add a new case into the switch block. However, this solution has a few problems. In the future, we would like to use this switch block in multiple places in the solution (e.g. we could create a desktop or mobile version of our application). The maintenance of multiple equal blocks in the application is useless. Therefore, we can create one class (factory) in which this switch block will be implemented. This is the main reason for the factory — create one or multiple objects.
All files in this setcion create into StatProjectLib/Factories/
We shouldn’t forget about abstraction, so let’s start with interface implementation. Set the interface name to IFactory and define the method Create with the parameter function name. We can use generics techniques in order to recycle this interface in the future.
The factory class SimpleCommandFactory implements the interface IFactory. As you can see, we replace generic T with ISimpleCommand interface (because each Command class implements ISimpleCommand). In the method Create is placed mentioned switch block.
You can find another implementation of the abstract factory on the Internet. Typically, these implementations implement one method for each option (in our case, for each command class). But in the end, you also have to implement one method with switch blocks.
Custom abstract factory
Although the above implementation is suitable for our scenario, I would like to show you my solution. As you can see, the implemented abstract factory contains direct references to the Command classes through their constructors (new AverageCommand(), etc.). A better solution is to use only abstractions (ISimpleCommand).
We could inspire by ASP .NET IoC implementation and use C# functions (Func<T>). Func is a simple notation for delegate. A delegate is a pointer to a method with specific parameters and return type. If you call delegate, it calls the method it points to. In our example, we will use only Func<ISimpleCommand> delegates. It means the delegate requires return type ISampleCommand (without any parameters). In the code block below, you can see a small example of initialization and calling delegates.
In my implementation of the abstract factory, I use also the method Create (in order to select right statistical function). However, I don’t use switch block with direct references. The factory contains another method — Register, in which I add delegates with function names. I decided to use two different methods Register (I will explain later). Let’s look at the interface (IMyFactory).
In my implementation, the abstract factory holds the dictionary attribute _commands. The keys represent function names and values are delegates returning ISimpleCommand.
_commands = new Dictionary<string, Func<ISimpleCommand>>();
Method Create only finds value in the dictionary and calls delegate if exists.
The first register method just takes the function name and delegate from parameters and puts them into the dictionary.
The second method is more interesting because it uses another generic U. However, U must contain a non-parametric constructor and implement ISimpleCommand. So, you don’t have to implement any new constructor, just replace U with the name of the Command class.
The code of complete class is
Now, let’s look at the design. The factory doesn’t know anything about Command classes. It uses only ISimpleCommand. If we implement a new Command class, we would not edit our factory. This principle is called dependency inversion.
Finally, we are done with part 2! In the next (last) part, we will implement a simple controller and add our factory to IoC container.