Is this a good pattern? It has a code smell to me with having a factory class aware of the IUnityContainer…
My basic need was to resolve an ICalculationRuleProcess at runtime depending on an Id of a class. It could be based on something other than the Id, I am aware of that… basically I have a known set of Ids that I need to deal with because I bootstrapped the records into the database manually and there is no way to edit the records. With each Id I have a related class. I also have a varying number of constructor parameters within each class that implements the ICalculationRuleProcess, so using an IoC container is extremely helpful versus some crazy switch statement and variable constructor aguments using Activator.CreateInstance
Here is what I did:
- Registered the IUnityContainer instance within the container itself. I wasnt sure if this was even possible, but it worked.
- Registered all of the ICalculationRuleProcess classes with a unique identifier within the registration (basically just the Id.ToString() of each possible DistributionRule)
- Created a factory to determine the correct ICalculationRuleProcess, and had it use the IoC container to figure out the correct class to load.
- Registered the factory class (ICalculationRuleProcessFactory) to the IoC container
- Wherever the ICalculationRuleProcess needed to be used, I had the class take an ICalculationRuleProcessFactory in its constructor and have it call the Create method to figure out which ICalculationRuleProcess to use.
The code for the factory is here:
public interface ICalculationRuleProcessFactory
{
ICalculationRuleProcess Create( DistributionRule distributionRule );
}
public class CalculationRuleProcessFactory : ICalculationRuleProcessFactory
{
private readonly IBatchStatusWriter _batchStatusWriter;
private readonly IUnityContainer _iocContainer;
public CalculationRuleProcessFactory(
IUnityContainer iocContainer,
IBatchStatusWriter batchStatusWriter )
{
_batchStatusWriter = batchStatusWriter;
_iocContainer = iocContainer;
}
public ICalculationRuleProcess Create( DistributionRule distributionRule )
{
_batchStatusWriter.WriteBatchStatusMessage(
string.Format( "Applying {0} Rule", distributionRule.Descr ) );
return _iocContainer.Resolve<ICalculationRuleProcess>(
distributionRule.Id.ToString() );
}
}
This seems okay to me, given the constraints you described. The most important thing is that all of your rules implement
ICalculationRuleProcessand that all consumers of those rules only know about that interface.It isn’t inherently bad that your factory takes the container dependency, especially as an interface. Consider that if you ever had to change container implementations, you could create an
IUnityContainerimplementation that doesn’t use Unity at all (just forward all the members of the interface to their corresponding methods in the replacement container).If it really bothers you, you can add yet another layer of indirection by creating an agnostic IoC interface with the requisite
Register,Resolve, etc. methods and create an implementation that forwards these to Unity.