Factory Pattern in .NET - super easy with H.Necessaire
How to easily do factory pattern in .NET using H.Necessaire.
Context
Let's say we want to develop a test data generator for some primitive types.
We start by modelling the abstraction of such a generator.
public interface ImADataGenerator
{
string GenerateNewValue();
}
Then the abstraction of the factory.
public interface ImADataGeneratorFactory
{
ImADataGenerator GetGeneratorFor(Type primitiveType);
}
Then the testing runtime.
class Program
{
public int Main(string[] args)
{
ImADataGeneratorFactory dataGeneratorFactory; //Will instantiate once we have the concrete implementation
string intValue = dataGeneratorFactory.GetGeneratorFor(typeof(int)).GenerateNewValue();
string boolValue = dataGeneratorFactory.GetGeneratorFor(typeof(bool)).GenerateNewValue();
string doubleValue = dataGeneratorFactory.GetGeneratorFor(typeof(double)).GenerateNewValue();
string stringValue = dataGeneratorFactory.GetGeneratorFor(typeof(string)).GenerateNewValue();
}
}
The magic - concrete implementation
The concrete factory
class DataGeneratorFactory : ImADataGeneratorFactory
{
public ImADataGenerator GetGeneratorFor(Type primitiveType)
{
Type type = typeof(ImADataGenerator).GetAllImplementations().FirstOrDefault(x => x.IsMatch(primitiveType.Name));
if(type is null)
return null;
return (Activator.CreateInstance(type) as ImADataGenerator);
}
}
The concrete generators
class Int32DataGenerator : ImADataGenerator
{
public string GenerateNewValue() => 17;
}
class StringDataGenerator : ImADataGenerator
{
public string GenerateNewValue() => Guid.NewGuid().ToString();
}
///And so on...
That's it. Easy. 💖
As you can see, the factory identifies the concrete implementation based on the type name. The starting part of it to be more specific.
The match is case-insensitive.
If the type name doesn't match, the IsMatch()
extension method tries to find the concrete implementation via two more attributes from H.Necessaire:
Furthermore, if you're using the DI framework of H.Necessaire, things get even easier:
ImADependencyProvider dependencyProvider;
ImAnAbstractType concrete = dependencyProvider.Build<ImAnAbstractType>(concreteID);
Visit: H.Necessaire