使用设计模式构建通用数据库访问类


Factory设计模式

含义:定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。我们这里可能会处理对多种数据库的操作,因此,需要首先定义一个操纵数据库的接口,然后,根据数据库的不同,由类工厂决定实例化哪个类。
   下面,我们首先来定义这个访问接口。为了方便说明问题,我们为这个类定义了比较少的方法,其他的方法是很容易参照添加的。同时注意,我这里使用了abstract class来定义这个访问接口,而不是interface,理由在后面可以看到。

定义一个抽象类:

public abstract class DBOperator 
   { 
   
public abstract IDbConnection Connection{get;} //得到数据库连接 
   public abstract void Open(); //打开数据库连接 
   public abstract void Close(); //关闭数据库连接 
   public abstract void BeginTrans(); //开始一个事务 
   public abstract void CommitTrans(); //提交一个事务 
   public abstract void RollbackTrans(); //回滚一个事务 
   public abstract void exeSql(string strSql,string[] strParams,object[] objValues); 
   
//执行Sql语句,没有返回值 
   public abstract DataSet exeSqlForDataSet(string QueryString);
  
//执行Sql,返回DataSet 
   } 

我们编写数据访问的具体实现类:
Sql Server的数据库访问类:  

internal class SqlDBOperator: DBOperator  
  {    
         
private SqlConnection conn;
         
//数据库连接
         private SqlTransaction trans;
         
//事务处理类    
         private bool inTransaction=false;
         
//指示当前是否正处于事务中    
  public override IDbConnection Connection  
    {      
     
get{
        
return this.conn;
        } 
    } 
   
//SQL数据库的连接方法  
  public SqlDBOperator(string strConnection)
    {   
   
this.conn= new SqlConnection(strConnection);  
    }
 
//打开数据连接    
  public override void Open()  
    {    
  
if(conn.State.ToString().ToUpper()!="OPEN")
    
this.conn.Open();
    } 
 
//关闭数据连接  
  public override void Close()   
    {   
   
if (conn.State.ToString().ToUpper()=="OPEN")
     
this.conn.Close();   
    }
 
//打开事务处理机制 
  public override void BeginTrans()   
    { 
    trans
=conn.BeginTransaction() ;   
   inTransaction
=true
    }
 
//提交事务处理机制  
  public override void CommitTrans()   
    { 
    trans.Commit();   
   inTransaction
=false;  
    } 
  
//回滚事务处理机制   
  public override void RollbackTrans()
    {   
   trans.Rollback();   
   inTransaction
=false;   
    }
  
//执行SQL语句的操作,无返回值    
  public override void exeSql(string strSql,string[] strParams,object[] strValues)  
    {     
    SqlCommand cmd
=new SqlCommand(); 
    cmd.Connection
=this.conn ;   
   
if(inTransaction)      
   cmd.Transaction
=trans;     
    
if((strParams!=null)&&(strParams.Length!=strValues.Length) )  
     
throw new ParamValueNotMatchException("查询参数和值不对应!");  
     cmd.CommandText
=strSql;    
   
if(strParams!=null)   
       {    
      
for(int i=0;i<strParams.Length;i++)  
         cmd.Parameters.Add(strParams[i],strValues[i]); 
       }   
   cmd.ExecuteNonQuery();  
    }
 
//重载执行SQL语句的操作,返回数据集 
  public override DataSet exeSqlForDataSet(string QueryString)  
    {     
      SqlCommand cmd
=new SqlCommand(); 
       cmd.Connection
=this.conn ;  
     
if(inTransaction)     
       cmd.Transaction
=trans;     
      DataSet ds 
= new DataSet(); 
     SqlDataAdapter ad 
= new SqlDataAdapter();   
     cmd.CommandText
=QueryString;   
     ad.SelectCommand 
=cmd;     
      ad.Fill(ds);     
      
return ds;    
  }   

Oledb的数据库访问类:

internal class OleDBOperator : DBOperator 
 {    
   
private OleDbConnection conn; 
   
private OleDbTransaction trans; 
   
private bool inTransaction=false
   
public OleDBOperator(string strConnection) 
   { 
    
this.conn= new OleDbConnection(strConnection); 
   } 
   
public override IDbConnection Connection 
   { 
    
get
        {
         
return this.conn;
        } 
   } 
   
public override void Open() 
   { 
   
if(conn.State.ToString().ToUpper()!="OPEN"
   
this.conn.Open(); 
   } 
   
public override void Close() 
   { 
   
if (conn.State.ToString().ToUpper()=="OPEN"
       
this.conn.Close(); 
   } 
   
public override void BeginTrans() 
   { 
     trans
=conn.BeginTransaction() ; 
     inTransaction
=true
   } 
   
public override void CommitTrans() 
   { 
     trans.Commit(); 
     inTransaction
=false
   } 
   
public override void RollbackTrans() 
   { 
     trans.Rollback(); 
     inTransaction
=false
   } 
   
public override void exeSql(string strSql,string[] strParams,object[] strValues) 
   {   
       OleDbCommand cmd
=new OleDbCommand(); 
      cmd.Connection
=this.conn ; 
       
if(inTransaction) 
     cmd.Transaction
=trans; 
       
if((strParams!=null)&&(strParams.Length!=strValues.Length) ) 
       
throw new ParamValueNotMatchException("查询参数和值不对应!"); 
       cmd.CommandText
=this.ChangeQueryString(strSql); 
       
if(strParams!=null
         { 
          
for(int i=0;i<strParams.Length;i++
              cmd.Parameters.Add(strParams[i],strValues[i]); 
         } 
     cmd.ExecuteNonQuery(); 
   } 
   
public override DataSet exeSqlForDataSet(string QueryString) 
   { 
     OleDbCommand cmd
=new OleDbCommand(); 
       cmd.Connection
=this.conn ; 
     
if(inTransaction) 
     cmd.Transaction
=trans; 
     DataSet ds 
= new DataSet(); 
     OleDbDataAdapter ad 
= new OleDbDataAdapter(); 
       cmd.CommandText
=QueryString; 
     ad.SelectCommand 
=cmd; 
     ad.Fill(ds); 
     
return ds; 
     } 
   } 
我们需要创建一个Factory类,来实现自动数据库切换的管理。这个类很简单,主要的功能就是根据数据库连接字符串,判断使用什么数据库,然后,返回适当的数据库操纵类。在这里,判断的方法很简单,只是根据两种数据库连接字符串的不同来判断。在实际中,随着数据库类的增加,判断的方法可能会有所变化。 
 public class DBOperatorFactory 
   { 
    
public static DBOperator GetDBOperator(string strConnection) 
     { 
    
if(strConnection.IndexOf("provider=")<0//SqlServer 
        { 
    
return new SqlDBOperator(strConnection); 
         } 
    
else //other database 
        { 
    
return new OleDBOperator(strConnection); 
        } 
     } 
   } 
客户端在代码调用的时候,可能就是采用如下形式:
 DBOperator db=DBOperatorFactory.GetDBOperator(strConnection) 
     db.Open(); 
     db.需要的操作 
     db.Close(); 
   或者: 
   DBOperator db
=DBOperatorFactory.GetDBOperator(strConnection) 
   db.Open();db.BeginTrans(); 
   
try 
   { 
   db.需要的操作 
   db.CommitTrans(); 
   } 
   
catch 
   { 
    db.RollbackTrans(); 
   } 
  db.Close(); 
当数据库发生变化的时候,DBOperatorFactory会根据数据库连接字符串自动调用相应的类,客户端不会感觉到变化,也不用去关心。这样,实现了良好的封装性。当然,前提是,你在编写程序的时候,没有用到特定数据库的特性,例如,Sql Server的专用函数。
   实际上,Factory模式也可以不使用Factory类来实现,而是让接口抽象类自己来管理,这可以称作自管理的Factory,是Factory模式的一种变形。这么做的好处,是可以免去一个Factory类,使代码更加简练。这么做,我们需要对DBOperator类做一些改变,增加一个Instance方法。这也是对DBOperator采用抽象类而不是接口的原因(接口的方法不能有实现),代码如下: 

public static DBOperator Instance(string strConnection) 
   {   
     
if(strConnection.IndexOf("provider=")<0//SqlServer 
       { 
          
return new SqlDBOperator(strConnection);    
       } 
      
else //other database 
       {
           
return new OleDBOperator(strConnection);   
       } 
   } 
Singleton设计模式
  含义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。推而广之,当我们需要精确控制类在系统中的实例的个数的时候,就可以使用Singleton模式。现在,我们需要构建一个缓冲池,保存数据库类的实例,正好是Singleton模式发挥作用的时候

我们仍然让DBOperator类自己来管理这个缓冲池,为了实现这个目的,我们需要对DBOperator类做一些变化:  
首先,增加两个变量:
static DBOperator[] ConnectionPool=new DBOperator[int.Parse ConfigurationSettings.AppSettings["PoolCount"])];

static int CurrentPosition=-1;

然后,对Instance方法做一些改变: 

public static DBOperator Instance(string strConnection) 
   { 
   
if(ApplicationConfiguration.PooledConnectionCount<1//没有缓冲 
     { 
      
return CreateNewDBOperator(strConnection);  
     } 
   
else 
     { 
      CurrentPosition
++
      
if(CurrentPosition==ApplicationConfiguration.PooledConnectionCount) 
        CurrentPosition
=0
      
if(ConnectionPool[CurrentPosition]==null
       {
       ConnectionPool[CurrentPosition]
=CreateNewDBOperator(strConnection);   
      } 
     
return ConnectionPool[CurrentPosition]; 
     } 
  } 
 
private static DBOperator CreateNewDBOperator(string strConnection) 
   { 
    
if(strConnection.IndexOf("provider=")<0//SqlServer 
      { 
      
return new SqlDBOperator(strConnection);  
     } 
     
else //other database 
      { 
     
return new OleDBOperator(strConnection);   
     } 
   } 

这样就完成了!

posted @ 2007-09-06 16:41  herobeast  阅读(698)  评论(0)    收藏  举报