zoukankan      html  css  js  c++  java
  • 设计模式学习(二)

       在这边博客设计模式学习(一)中,我分别写了操作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,但是如何方便的让程序在两种数据库之间切换,仍然是一个值得思考的问题,请关注我以后的博文。

  • 相关阅读:
    fatal error C1902: 程序数据库管理器不匹配;请检查安装 (zz)
    c++ std string reserve 测试
    2018年长沙理工大学第十三届程序设计竞赛
    2018年东北农业大学春季校赛
    从本质看海明码——海明码的由来
    CodeForces475
    一维背包问题
    2018年长沙理工大学第十三届程序设计竞赛 箱庭的股市
    高精度加法模板
    for,while,do while
  • 原文地址:https://www.cnblogs.com/xianrongbin/p/2834640.html
Copyright © 2011-2022 走看看