Refactoring in C# & ASP.NET – Abstract Factory with Reflection

In the Wrox book Professional Refactoring in C# & ASP.NET, author Danijel Arsenovski discusses creating data providers through the Abstract Factory Pattern. Here, I discuss an alternative method for implementing this pattern.




The Abstract Factory Pattern is discussed in Chapter 12 of the aforementioned book. In brief, this pattern allows us to “plug in” an appropriate provider at runtime, by implementing the following steps:

  1. Create an abstract factory class that defines interfaces for the creation of related objects.
  2. Use concrete factories that inherit the abstract factory and override its abstract methods.

In Listing 12-12, the author shows the following implementation:

public static DataProviderFactory CreateDataProviderFactory(
    String providerName)
{
    DataProviderFactory concreteFactory = null;
    switch (providerName) { 
        case DataProviderFactory.MsSqlProviderName:
            concreteFactory = new MsSqlProviderFactory();
            break;
        case DataProviderFactory.OracleProviderName:
            concreteFactory = new OracleProviderFactory();
            break;
        case DataProviderFactory.OleDbProviderName:
            concreteFactory = new OleDbProviderFactory();
            break;
    }
    return concreteFactory;
}

Using a switch switch statement is a common method of instantiating concrete factories. However, as the author points out on page 375, there are problems with doing this.

The Open-Closed Principle states that an object should remain open for extension, but closed for modification. When you use a switch statement as shown above, you must modify the DataProviderFactory class by adding a new case block for each new concrete provider factory you wish to implement. Since the class cannot be extended without modification, it does not adhere to the Open-Closed Principle.

One solution to this is to instantiate the factory by means of reflection.

namespace Users
{
   using System;
   using System.Configuration;
   using System.Data;
   using System.Reflection;

   public abstract class DataProviderFactory
   {
      private static string providerName;
      private static DataProviderFactory instance;

      public static string ProviderName
      {
         private get { return providerName ?? "System.Data.OleDbClient"; }
         set { providerName = value; }
      }

      public static DataProviderFactory Instance
      {
         get
         {
            if (instance == null)
            {
               foreach (Type type in Assembly.GetExecutingAssembly().GetTypes())
               {
                  if (type.BaseType == typeof(DataProviderFactory))
                  {
                     string provider = type.GetField("Provider").GetRawConstantValue().ToString();

                     if (provider == ProviderName)
                     {
                        instance = (DataProviderFactory)Activator.CreateInstance(type, true);
                        break;
                     }                     
                  }
               }                                            
            }

            return instance;
         }
      }

      public abstract IDbConnection Connection { get; }

      public abstract IDbCommand Command { get; }

      protected static string ConnectionString
      {
         get
         {
            ConnectionStringSettingsCollection settings = ConfigurationManager.ConnectionStrings;

            foreach (ConnectionStringSettings setting in settings)
            {
               if (setting.ProviderName == ProviderName)
               {
                  return setting.ConnectionString;
               }
            }

            return null;
         }
      }
   }
}

Here, instead of a CreateDataProviderFactory method, we use a static Instance property, which can be invoked as follows:

private void delete_Click(object sender, EventArgs e)
{
   DataProviderFactory factory = DataProviderFactory.Instance;

   IDbConnection connection = factory.Connection;
   IDbCommand command = factory.Command;

   // ... rest of code ...
}

Note that I’ve composed the DataProviderFactory class as a singleton. The Instance property is written in such as way that no more than one instance of any concrete provider can exist. To enforce the singleton behavior, the access level of the constructors for the three concrete providers have been changed to protected.

namespace Users
{
   using System.Data;
   using System.Data.SqlClient;

   public class MsSqlProviderFactory : DataProviderFactory
   {
      public const string Provider = "System.Data.SqlClient";

      protected MsSqlProviderFactory()
      {
      }

      public override IDbConnection Connection
      {
         get { return new SqlConnection(ConnectionString); }
      }

      public override IDbCommand Command
      {
         get { return new SqlCommand { Connection = (SqlConnection) this.Connection }; }
      }
   }
}

This prevents methods that consume the provider from instantiating it in any other way except through the Instance  property. In other words, it prevents you from doing the following:

private void delete_Click(object sender, EventArgs e)
{
   DataProviderFactory factory = new MsSqlProviderFactory();

   IDbConnection connection = factory.Connection;
   IDbCommand command = factory.Command;

   // ... rest of code ...
}

If you’re interested in examining how this works in practice, I’ve created a downloadable sample which shows it in action. Enjoy!


For more cool stuff, be sure to visit my regular blog and follow me on Twitter.

Tags:

Comments

2 responses to “Refactoring in C# & ASP.NET – Abstract Factory with Reflection”

  1. Anonymous says:

    great piece of coding .. I learnt a lot cheers  ..

  2. Marck says:

     It’s a great Idea! Thanks for sharing.
    I have a Base class where my business class have a inheritence. So, i need a way to know if i have a subclass of my default subclass, like this:
     
    public class Base{}
    public class OrderBll : Base{}
    public class CustomOrder : OrderBll
     
    My client call OrderBll class like this:
    OrderBll orderbll = new OrderBll();
    but, the concrete type, now with your code, should return a CustomOrder instance. It’s very smart!
    In my base class, i created a prop called ISelf, and a access method for it:

    get

    {
    if (iself == null)
    {
    foreach (Type type in Assembly.GetExecutingAssembly().GetTypes())
    {
    if (type.BaseType == this.GetType() && !type.Name.Equals(this.GetType().Name))
    {
    iself = (Base<TSource>)Activator.CreateInstance(type, true);
    break;
    }
    }
    }

    //do a new test to verify if dont have subclasses
    return iself == null ? this : iself;
    }
     
     
    Thanks!

Leave a Reply

Your email address will not be published. Required fields are marked *