鲜荣彬
Herry

   在这边博客设计模式学习(一)中,我分别写了操作Sql Server与Oracle数据库的DBHelper两个帮助类(一个GetTable()方法),但我认为不方便,于是开始研究是否可以只写一个类,就可以操纵两种数据库呢,于是便开始了分析。

  经过分析,在查看OracleConnectionSqlConnection两个类时,有如下的发现:

  public sealed class SqlConnection : DbConnection, ICloneable

  public sealed class OracleConnection : DbConnection, ICloneable

  这让我十分的惊异,因为他们都继承DbConnection类,更让我惊异的是DbConnection类是一个抽象类,而且实现了IDbConnection接口,代码如下:

  public abstract class DbConnection : Component, IDbConnection, IDisposable

  不仅如此,SqlCommandOracleCommand都  继承DBCommand

       SqlDataAdapterOracleDataAdapter都继承DbDataAdapter, IDbDataAdapter, IDataAdapter。

  因此,我觉得这应该是net框架里面一种的模式,而且很有可能是抽象工厂模式,而不是工厂模式(工厂模式解决的是某个对象的创建工作,这个对象面临着剧烈的变化,但是拥有比较稳定的接口,因此,我们可以使其成为抽象类,最后让一个子类具体去实现这个抽象类),这里的DBConnection、DBCommand、DBDataAdapter、DBDataReader四个类的实现应该是工厂模式(如果理解有误,请指正)。

  那么有了工厂模式会什么还会有抽象工厂模式呢?这是因为简单工厂模式不能应对不同系列对象的变化。抽象工厂模式的动机与意图如下:

  动机:在软件系统中,经常面临着一系列相互依赖的对象的创建工作,同时,由于需求的变化,往往存在更多系列对象的创建工作。

  意图:提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需制定它们具体的类。(GOF)

  在这里,Connection、Command、DataAdapter、DataReader四个对象,是相互依赖的,可以操作Sql Server、Oracle、Access等数据库。因此,根据上面的动机与意图,可以判定这是抽象工厂模式。

  请看下图:

  

   在这张图左上角有一个工厂DbProviderFactories,这个静态类可以通过参数为抽象工厂DbProviderFactory提供一个具体的工厂,即可以使SqlClientFactory,也可以是OracleClientFactory工厂。有了DbProviderFactory这个抽象工厂,那么我们就可以只写一个类,就可以根据配置文件来得到具体的工厂,通过一个具体的工厂,可以操作具体的数据库,这样我的目标就实现了(这个DbProviderFactories抽象工厂并没有实现MySqlClientFactory,如果要与MySql数据库交互,则需自己想办法了)。

  只需写一个类,就可操作两种不同的数据库,或者多种数据库,多么方便啊。

  新建一个DataDBHelper,这里写了一个GetDataTable()示例方法获得表数据,代码如下:

public class DataDBHelper
    {
        private string providerName="";//数据库提供者
        private string strConn="";//连接数据库字符串
        DbProviderFactory factory = null;//工厂提供者
        public DataDBHelper()
        {
            providerName = ConfigurationManager.AppSettings["DBProvider"].ToString();
            //如果是Sql Server数据库配置文件则是 System.Data.SqlClient 如果是Oracle数据库 则是System.Data.OracleClient
            strConn = ConfigurationManager.ConnectionStrings["conStr"].ConnectionString;
            factory = DbProviderFactories.GetFactory(providerName);//创建工厂
        }
public DataTable GetDataTable(string strSql, params DbParameter[] param)
        {
            using (DbConnection conn = factory.CreateConnection())//创建连接
            {
                conn.ConnectionString = strConn; //赋予连接字符串
                using (DbCommand cmd = factory.CreateCommand())
                {//创建Sql命令
                    cmd.CommandText = strSql;                //赋值Sql命令语句
                    cmd.Connection = conn;
                    DbParameter dbParam = factory.CreateParameter(); //参数赋值
                    if (param.Length > 0)
                    {
                        for (int i = 0; i < param.Length; i++)
                        {
                            dbParam.ParameterName = param[i].ParameterName;
                            dbParam.Value = param[i].Value;
                        }
                        cmd.Parameters.Add(dbParam);
                    }

                    DbDataAdapter adapter = factory.CreateDataAdapter(); //创建适配器
                       adapter.SelectCommand = cmd;

                    DataTable dt = new DataTable();
                    conn.Open();
                    adapter.Fill(dt);
                    conn.Close();
                    return dt;
                }
            }
        }

   其中,SQL Server数据库的配置文件如下:

  <connectionStrings>
    <add name="conStr"  connectionString="Data Source=xianrongbin-pc;Initial Catalog=TestFactory;User Id=sa; Password=123456;"/> 
  </connectionStrings>

  <appSettings >
    <add key="DBProvider" value="System.Data.SqlClient"/>
  </appSettings>

    Oracle数据库的配置文件如下


<connectionStrings>
   
   <add name="conStr" connectionString="data source=orcl;User Id=scott;Password=m123;">
 
</connectionStrings>
<appSettings >
   
  <add key="DBProvider" value="System.Data.OracleClient"/>
 
</appSettings>

  那么如何调用GetDataTable()这个方法呢,我想,应该是很好调用的,示例代码如下

 DataDBHelper dbHelper = new DataDBHelper();
  SqlParameter parms
= new SqlParameter("@ID", "2"); DataTable dtSqlInfo = dbHelper.GetDataTable("select * from FactoryTable where id>@ID", parms); //SQl Server调用

OracleParameter param =new OracleParameter(":empno","7369");select ename from emp where empno=:empno

  DataTable dtOracleInfo = dbHelper.GetDataTable("select * from FactoryTable where id>@ID", parms); //Oracle调用

  从上面的代码我们可以看到,原本需要写两个数据库帮助类,现在只需要写一个类了,减少了代码的数量;其次,在数据层中,我们只需要new一个DataDBHelper类,往其传入相应的参数,然后就可以调用对应的方法得到对应的值,而不需要去判断new SqlHelper()还是new OracleHelper()。

  使用Abstract Factory 模式需要注意下面几个要点:

  1、如果没有应对“多系列对象构建”的需求变化,则没有必要使用此模式,只有一个对象的需求变化,就完全可以使用静态工厂模式。

  2、“系列对象指的是这些对象之间有相互依赖或作用的关系。如DbConnection与DbCommand。

  3、Abstract Factory模式主要在于应对“新系列”的需求变动,其缺点在于难以应对“新对象”的需求变动。

  4、Abstract Factory常常与工厂模式共同组合应对“对象创建”的需求变动。微软的例子我们可以明显看到,DBConnection本身就是一种工厂模式。

  虽然搞定了DBHelper,但是如何方便的让程序在两种数据库之间切换,仍然是一个值得思考的问题,请关注我以后的博文。

posted on 2012-12-26 21:57  Herry彬  阅读(1678)  评论(2编辑  收藏  举报