Design patterns really are quite useful. I have a situation in the code I’m working on where I was obviously repeating a lot of the same patterns and code (functions that were 90% the same–the only thing different was the specific class being instantianted): perfect candidate for factory techniques.
Let’s say we have the following set of classes representing a data access layer meant to abstract some database information from the client code. We have a BaseDBObject class that defines all of the common. We derive from that for each table we want to access.
class BaseDBObject
{
   protected BaseDBObject(Database database) {...}
   public void SetProperty(string name, object value) {...}
   //...more common functionality
};
Derived from this base are lots of classes that implement table-specific database objects. To control object creation, constructors are declared protected and static member functions are used. To wit:
class MyTableObject : BaseDBObject
{
   protected MyTableObject(Database database) : base(database) { }
   public static void Create(Database database, int param1, string param2)
   {
       string query = "INSERTO INTO MyTable (param1, param2) VALUES (@PARAM1, @PARAM2)";
       SqlCommand cmd = new SqlCommand(query, database.GetConnection());
       //paramterize query
       try {
           //exeute query
           //error check
           MyTableObject mto = new MyTableObject();
           //set object properties to match what's inserted
           return mto;
       }
       catch (SqlException ex)
       {
           //handle exception
       }
       finally
       {
           //close connection
       }   }
   //...
   public static IList<MyTableObject> LookupById(Database database, int id)
   {
       string query = "SELECT * FROM MyTable WHERE ID = @ID";
       SqlCommand cmd = new SqlCommand(query, database.GetConnection());
       //parameterize query
       try
       {
           //execute query
           SqlDataReader reader = cmd.ExecuteReader(...);
           List<MyTableObject> list = new List<MyTableObject>();
           while (reader.Read())
           {
               MyTableObject mto = new MyTableObject();
               //set properties in mto
               list.Add(mto);
              Â
           }
           return mto;
       }
       catch (SqlException ex)
       {
           //handle exceptions
       }
       finally
       {
           //close connections
       }
   }
};
There are two functions here that must be created for every single table object derivation. That can be a LOT of code, and most of it is doing the same thing. There are a number of simple ways to handle some of the repetition:
- There will be multiple LookupByXXXXX functions. They can all specify the query they will use and pass it to a common function that executes and returns a list the class’s objects.
- Paramterizing queries can be accomplished by a function that takes a query string, a list of parameters (say, in a struct that describes each parameter), and produces a paramterized SqlCommand, ready for execution.
- Other helper functions that do the actual execution and checking of errors.
In the end, however, you are still left with two things that can’t be relegated to helper functions: MyTableObject mto = new MyTableObject();
and List<MyTableObject> list = new List<MyTableObject>();
One possible solution is to use reflection to dynamically generate the required objects. From a performance and understandability perspective, I don’t think this is a first choice.
Which leaves a factory method. My first attempt involved using templates to simplify this (you will see why shortly). Something like this:
class DatabaseObjectFactory<T> where T : BaseDBObject, new()
{
   public T Create(Database database) { return new T(database); }Â
   public IList<T> CreateList() { return new List<T>(); }
};
This way, I could simply define a function in the base class BaseDBObject, which I could call like this:
Lookup(database, query, arguments, new DatabaseObjectFactory<MyTableObject>());
and that would automagically return a list of the correct objects. The problem with this approach, however, lies in the Create function. .Net can’t pass arguments to a constructor of T. It can only return new T() with no parameters. Nor can you access properties of BaseDBObject through T after creation. Back to the drawing board…
Now I had to face the problem of creating a duplicate inheritance hierarchy of object factories. This is what I had hoped to avoid by using generics. I designed an interface like this:
interface IDatabaseObjectFactory
{
   BaseDBObject Create(Database database);
   IList<BaseDBObject> CreateList();
};
And in each table object derivation I declare a private class and static member like this:
private class MyTableObject : IDatabaseObjectFactory
{
   public BaseDBObject Create(Database database) { return new MyTableObject(database); }
   public IList<BaseDBObject> CreateList() { return new List<MyTableObject>(); }
};private static IDatabaseObjectFactory s_factory = new MyTableObjectFactory();
Now, I can have a Lookup function in BaseDBObject that accepts an IDatabaseObjectFactory parameter. At the expense of creating a small, simple factory class for each table object that needs it, I can remove roughly 50 lines of code from each of those classes. Smaller code = fewer bugs and easier maintenance.
The base lookup function would look something like this:
protected Lookup(Database database, string query, ICollection<QueryArgument>, IDatabaseObjectFactory factory)
{
   //paramterize query
   //execute query
   //ignoring error-handling for sake of brevity
   SqlDataReader reader = cmd.ExecuteReader(...);
   IList<BaseDBObject> list = factory.CreateList();
   while (reader.Read())
   {
       BaseDBObject obj = factory.Create(database);
       obj.Fill(reader);   //another common function that
                            // automatically fills in all properties
                            //of object from SqlDataReader
       list.Add(obj);
   }
   return list;
}
But what about theMyTableObject.Create()? It’s possible to do something like this, but in a different way. In order to handle inserting rows in a table that uses identity fields (that you don’t know until after creation), I created a utility function that inserted the data using database, query string, and QueryArgument objects. Then, instead of creating the object directly, I do a Lookup based on values that I know are unique to the row I just inserted. This ensures I get the most complete object (at the expense of an extra database trip).