Dofactory.com
Dofactory.com
 Back to list
Views:   9.6K
Replies:  1
Archived

Abstract Factory - How to break down a large factory?

In the Patterns in Action solution of the Design Pattern Framework (v3.5) the data access layer uses the Abstrat Factory pattern to shield creation of data access objects from the client.  With a small number of data access objects this seems to be OK, however when modelling a database with hundreds of tables, the number of data access objects quickly grows and in turn results in large factories which each have to be updated when a table/data access object is added.

Is there a way to break down a large factory in some way to make it more maintainable and to adhere to the open closed principle?

One possible idea I can think of is to have a generic method as follows (where T would be a DAO Interface):

public T CreateInstance<T>()
{
    // Use reflection here to lookup a concrete type in the DataAccess assembly that implements T
}

then the business logic classes would have a private instance e.g.:

private static ICustomersDao _customerDao = DataAccess.CreateInstance<ICustomersDao>();


I think each DAO interface would need to inherit from a marker interface so that a generic constraint could be placed on the method to limit the types that could be returned.

Assuming the data access layer supports SQL, Oracle, etc, then the CreateInstance<T>() method would have to only lookup concreate classes in the relevant namespace, so if the DB provider was set to 'System.Data.SqlClient' in the config then we would only want to find a concrete class in the SqlServer DAO namespace.

Would this work?  Any other suggestions?

Matt Fothergill, Mar 25, 2011
Reply 1
Generics approach will work.  I have implemented my own custom DAL 5 years back and it is still going smooth (no exaggeration here).

The approach is similar to what is in EF , but with a twist.  Just to outline how it works (there are no class clutters)..

Assume there is a Customer table in the DB.  The entity is modelled as below

[Table ("ebCustomerMaster")]
public class Customer
{
    [Column()]
     public Guid Id {
             get { return id; }
             set { id = value; }
     }

    [Column()]
     public string Name{
             get { return name; }
             set { name = value; }
     }
}

I am just displaying a subset of properties.  Note this class is auto generated by a custom utility.

Now we have a SmartData<T> class which is responsible for generating the SQL based on xml file (as this was our requirement).

A sample insert function in the SmartData is displayed below.


    public class SmartData<T>
    {

        public int Insert(T obj, string spName)
        {
            DataRow queryRow = dsSQL.Tables["Query"].Select("Id = '" + spName + "'")[0];

            string commandText = queryRow["CommandText"].ToString();
            string commandType = queryRow["CommandType"].ToString();

            Request request = new Request();
            request.CommandText = commandText;

            request.CommandType = (CommandType)Enum.Parse(typeof(CommandType), commandType);
            ProcessParameter(obj, request);

            return dbEngine.Insert(request);
        }
       
         // MORE functions goes here....
        
}

NOTE : Here there is no scope for SQL injection attach as the actual sql is not built here....

Then there's a DB engine which is responsible for talking with the underlying dtabase.

The DBEngine's Insert function is shown below...

        public int Insert(Request request)
        {
            using (DbCommand command = factory.CreateCommand())
            {
                int ret = 0;
                //if (null == connection || connection.State != ConnectionState.Open)
                OpenConnection();

                command.Connection = connection;
                if (request.Parameters.Count > 0)
                {
                    foreach (Parameter para in request.Parameters)
                    {
                        DbParameter p1;
                        switch (dataProvider)
                        {
                            case "System.Data.OleDb":
                                p1 = new System.Data.OleDb.OleDbParameter(para.ParameterName, para.Value);
                                p1.DbType = GetDbTypeFromString(para.DataType);
                                command.Parameters.Add(p1);
                                break;
                            case "System.Data.SqlClient":
                                p1 = new System.Data.SqlClient.SqlParameter(para.ParameterName, para.Value);
                                p1.DbType = GetDbTypeFromString(para.DataType);
                                command.Parameters.Add(p1);
                                break;
                            default:
                                command.Parameters.Add(para);
                                break;
                        }
                    }
                }

                command.CommandText = request.CommandText;
                command.CommandType = request.CommandType;
                command.CommandTimeout = 0;

                ret = command.ExecuteNonQuery();
           
                return ret;
            }

The actual code may differ than what is shown here....

The good thing is there are no sub classes or any other helpers apart from the usual Service layer....
The DBEngine abstracts away the providers.  The query details in the XML gives us the flexibility to switch to stored procedures
or plain SQL queries at will.

Switching providers is as easy as creating a new xml file and updating only specifics which changes (in most cases
sql server, mysql, and oracle, most of the things are same)......


NOTE and suggestion:  I had taken this approach when EF was not available (or was in early stages) and data access  block
was also in  a very early stage.

I will recommend you also have a look at the MS Enterprise Library Data access blocks as well.  But don't be afraid to roll out your own if need arises.

This custom solution has provided me with a lot of flexibility in  a real enterprise application handling about 400 tables of data entry and about 1000 reports.... So, you can imagine the magnitude of usage of this library.. The only thing is it is not opensource, but there are various similar implementations available, and if you need to roll out, you can quickly do so... It's not that complex.

Hope this helps !




Rajesh Pillai, Mar 25, 2011
Stay Inspired!
Join other developers and designers who have already signed up for our mailing list.
Terms     Privacy     Cookies       Do Not Sell       Licensing      
Made with    in Austin, Texas.  - vsn 44.0.0
© Data & Object Factory, LLC.