Friday, March 30, 2012

Simple factory, Dependency Injection and Unity

Someone asked me the question whether a simple factory can be implemented using dependency injection container. The example he bought up is where a simple factory takes in a string and switches this string to return the correct instance of the object needed....I am talking about something like this.

internal IWaterMarkProvider GetProvider(string fileExtension)

{

IWaterMarkProvider provider = null;

switch (fileExtension.ToLower())

{

case "pdf":

provider = new PDFProvider();

break;

case ".docx":

provider = new WordProvider();

break;

case "pptx":

provider = new PPTProvider();

break;

case "xlsx":

provider = new ExcelProvider();

break;

}

return provider;

}

The answer was yes..So, if you are using Microsoft Unity (a dependency injection container), you would have your configuration file like this...

<configuration>

<configSections>

<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>

configSections>

<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">

<container name="providerContainer">

<register type="TestLibrary.IWaterMarkProvider,TestLibrary" name="docx" mapTo="TestLibrary.WordProvider,TestLibrary" />

<register type="TestLibrary.IWaterMarkProvider,TestLibrary" name="pdf" mapTo="TestLibrary.PDFProvider,TestLibrary" />

<register type="TestLibrary.IWaterMarkProvider,TestLibrary" name="pptx" mapTo="TestLibrary.PPTProvider,TestLibrary" />

<register type="TestLibrary.IWaterMarkProvider,TestLibrary" name="xlsx" mapTo="TestLibrary.ExcelProvider,TestLibrary" />

<container>

<unity>

<configuration>

We are basically configuring a Unity container and configuring "named" registrations for the IWaterMarkProvider interface. So for an example, the named registration "docx" is mapped to the WordProvider. Hence when we resolve an instance for the IWaterMarkProvider passing the file extension "docx", the Unity container will create an instance of the WordProvider class.
The code below shows how to do this....

IUnityContainer container = new UnityContainer().LoadConfiguration("providerContainer");

IWaterMarkProvider provider = container.Resolve<IWaterMarkProvider>(fileType);

provider.WaterMark();


Note that "providerContainer" is the name of the container specified in the configuration file.
The "fileType" is a parameter that holds the type of the file e.g. "docx"
Whats the advantage of this approach to the approach that we initial put forward, that is with the simple factory we implemened in the first code listing?
First, the code for creation of these classes are "outsourced" and responbility of the container
Secondly, the providers can be changed without recompiling the source, this is even true when we add a new file type. We can just configure it on the configuration file.
Thirdly, If these providers depend on other types, the container will take care of injecting these types into the provider.
Another advantage (unreleated to this example) of using Unity, is that it promotes loose coupling. This becomes really easy when mocking while unit testing. As you can just point Unity to your mocks rather then the real dependencies.

Also note that the lifetime of the instances created through the container can be controlled. By default, each call to the container will create a new instance, if you want to have the WordProvider be a singleton, you can do this...

<register type="TestLibrary.IWaterMarkProvider,TestLibrary" name="docx" mapTo="TestLibrary.WordProvider,TestLibrary" >

<lifetime type="singleton"/>

register>

No comments:

Post a Comment