Understanding the Simple Factory Pattern

There are many sites out there showing examples of the Simple Factory Pattern.
This blog entry takes the simple examples a little further by giving 3 different ways to make the decision on which Concrete Object is returned.
 
While I have experience with all 3, the use of reflection seems to be the most powerful one.
 
Alot of times, you may be using this pattern (and specifically the #3 option) without really knowing it.
The Enterprise Library from Microsoft is one very well known Framework.  The DataAccess objects actually are using reflection to determine which concrete Database object (Microsoft.Practices.EnterpriseLibrary.Data.Database) to use.  The Microsoft.Practices.EnterpriseLibrary.Data.Database is an abstract class, and the concrete class is determined by some string settings in the dataConfiguration.config file.
(Look closely at the line
<databaseType name="Sql Server" type="Microsoft.Practices.EnterpriseLibrary.Data.Sql.SqlDatabase, Microsoft.EntLib.Data" />
That’s reflection giving back a concrete version of a Microsoft.Practices.EnterpriseLibrary.Data.Database object)
Here is another link, discussing the ASP.NET 2.0 Provider Model.
 
So what are the 3 methods?
 
1.  Using a "key".  Alot of web samples use this method.  The example here uses a string letter to give back a concrete IAnimal.
 
2.  Use the Environment.  I have to thank a previous colleague for showing me this one.  Well, he actually showed me the Factory Pattern to begin with.  So there’s some dap for him.
This example will return a different concrete class based on Web Environment or a Winforms environment.
 
3.  Using reflection.  You can setup the concrete class in a configuration file.  The code will use the Interface or Abstract Class, but you can switch out the functionality with just a tweak of a config file.
This is very flexible, and really keeps your options open for future development.
In fact, the concrete class can live in its own assembly, just as long as it implements the Interface or Abstract class.  My example shows how you can switch out to a different "RateQuoter" (the mock example uses PostalService and UPS to give different shipping rates).  The switch can occur without recompile, and only a few tweaks of a configuration file.
 
Thanks to all my colleagues with their mad OO skilllzzzz.
 
Here’s some code snipplets, the download will give you a complete C# code sample to show you how to better use the Factory Design Pattern.
As bonus material, you’ll also see a:
Web version of the Singleton Pattern.
A configuration handler, for encapsulating information in your App.config or Web.config file.
 
#1 Key Method
 
 public class AnimalFactory
 {
 
  public static IAnimal GetAnimal(string key)
  {
   switch (key.ToUpper())
   {
    case "B":
     return new Bird();
    case "C":
     return new Cat();
    case "D":
     return new Dog();
    default:
     throw new ArgumentException("The AnimalFactory was given a Bad Key");
    
   }
  }
 }
 
 
 #2  Environment Method
 
 public class ObjectHolderFactory
 {
  private ObjectHolderFactory()
  {
  }
  public static IObjectHolder GetObjectHolder( )
  {
   //This is a perfect example of a Simple Factory need.
   //When in a non web arena, the singleton is a simple
   //Hashtable or HybridDictionary object
   //When I am in the web arena, I need to piggyback off the
   //web Session object, aka, the WebSessionObjectHolder
   //uses session variables to store the singleton
   //Singleton
   if ( null == System.Web.HttpContext.Current ) // Add a reference to System.Web.dll
   { //Non Web Environment
    return InMemoryObjectHolder.GetInstance();
   }
   else
   { //Web Environment
    return WebSessionObjectHolder.GetInstance();
   }
  }
 }
 
 #3  Reflection
 
 public class RateQuoterFactory
 {
  private static readonly string CONFIG_SECTION_NAME = "RateQuotersSectionName";
  private RateQuoterFactory()
  {
  }
  public static IRateQuoter GetARateQuoter()
  {
   //The RateQuoterSettings encapulates the information found in the App.Config file
   //The "Handler" reads the xml … to create a RateQuoterSettings instance.
   RateQuoterSettings settings = ((RateQuoterSettings)System.Configuration.ConfigurationSettings.GetConfig(CONFIG_SECTION_NAME));
   //Now you have a RateQuoterSettings instance.
   //use the assembly and class name from the RateQuoterSettings instance. to dynamically create the object
   return CreateInstance( settings.AssemblyName, settings.ClassName , settings.ShippingCompanyHomeState  );
   
  }
  private static IRateQuoter CreateInstance( string assemblyName, string className , string homeState)
  {
   IRateQuoter returnObject = null;
   Assembly assem = Assembly.Load( assemblyName );
   if(null != assem) 
   {
    Type objectType = assem.GetType( className , true , true );
    //The use of "homeState" is here… to show how the CreateInstance can have non default constructors.
    //Notice the second argument is an array of objects.. the array of objects … needs to match one of the contructor-method-signatures
    returnObject = (IRateQuoter)Activator.CreateInstance( objectType , new object[] {homeState} );
   
   }
   return returnObject;
  
  }
 }
 
 
 <?xml version="1.0" encoding="utf-8" ?>
<configuration>
 <configSections>
  <section name="RateQuotersSectionName" type="GranadaCoder.Applications.FactoryPatternExamples.FactoryWithReflection.ConfigurationLib.RateQuoterHandler,GranadaCoder.Applications.FactoryPatternExamples" />
 </configSections>
 <RateQuotersSectionName>

  <rateQuoterObject enabled="true" assemblyName="GranadaCoder.Applications.FactoryPatternExamples.ConcreteObjectsOutsideBaseAssembly"
   className="GranadaCoder.Applications.FactoryPatternExamples.ConcreteObjectsOutsideBaseAssembly.ConcreteRateQuoters.UPSRateQuoter" ShippingCompanyHomeState="NC"/>

</configuration>
 
 
So there’s the summary.  Check out the code, and see for yourself.
  

Right click HERE and click ‘Save As’.

Advertisements
This entry was posted in Software Development. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s