"类工厂模式"改写SqlHelper

看到标题您必定很疑惑,23种经典设计模式何时多了一个"类工厂模式",稍等,请听我慢慢道来。程序员

实践是检验真理的惟一途径。最近用了"类工厂模式"改写了我公司的SqlHelper类,改写了一大半了,拿出半成品和你们一块儿讨论。sql

首先说下咱们公司环境:我公司在ABC三地都有工厂,同时都有各自的DB。通过调研,ABC三地的不少网页都有可有整合在一块儿的地方,我负责整合三地网页。数据库

一开始,没接触设计模式的时候。个人Sql是这样写的:"select * from "+ strSite +".dbo.Table where Id='XXX'".Sql语句中的strSite是从URL中得到的公司别。设计模式

这样能够经过strSite来区分ABC工厂的数据库。我是这样调用SqlHelper类的:DBA.GetDataTable("select * from "+ strSite +".dbo.Table where Id='XXX'");安全

一个Sql中不可能只有一个表,每写一个表,我就要在前面加上"+ strSite +",若是这样整合下去。公用页面的逻辑复杂了,并且在调试Sql语句的时候更是麻烦,常常由于少些后面的架构,或者多写DB的名称,致使系统报错。架构

知道了错误,就须要从错误中改变,我发现Sql中的strSite只是提供了一种环境,例如,strSite=A的时候,即为在A公司的DB中执行Sql,在B和C公司,一样是执行Sql的环境变了。ide

那我可不能够传一个参数,在SqlConnection的时候,动态的选择不一样的Sql环境。学习

咱爷们说干就干,因而就有了下面的代码:
spa

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Data.SqlClient;
 4 using System.Linq;
 5 using System.Text;
 6 using System.Threading.Tasks;
 7 
 8 public class DBAStore
 9 {
10     private static string AConnection = "A公司链接字符串";
11     private static string BConnection = "B公司链接字符串";
12     private static string CConnection = "C公司链接字符串";
13 
14 
15     public SqlConnection OrderSqlConnection(string strSite)
16     {
17         return GetConnection(strSite);
18     }
19 
20     // 获取SqlConnection方法
21 
22     private static SqlConnection GetConnection(string strSite)
23     {
24         switch (strSite)
25         {
26             case "A":
27                 return new SqlConnection(AConnection);
28             case "B":
29                 return new SqlConnection(BConnection);
30             case "C":
31                 return new SqlConnection(CConnection);
32             default:
33                 return null;
34         }
35     }
36 }
DBAStore
 1 using System;
 2 using System.Data;
 3 using System.Data.SqlClient;
 4 using System.Configuration;
 5 using System.Collections.Generic;
 6 using System.Web;
 7 using System.Web.Security;
 8 using System.Web.UI;
 9 using System.Web.UI.WebControls;
10 using System.Web.UI.WebControls.WebParts;
11 using System.Web.UI.HtmlControls;
12 using System.Collections;
13 
14 public class DBA
15 {
16     public DBA()
17     {
18         //
19         // TODO: Add constructor logic here
20         //
21     }
22     /// <summary>
23     /// 执行Sql返回DataTable(新版)
24     /// </summary>
25     /// <param name="strSite">公司别</param>
26     /// <param name="strSql">SQLStatement</param>
27     /// <returns></returns>
28     public static DataTable GetDataTable(string strSite, string strSql)
29     {
30         DBAStore dbaStore = new DBAStore();
31         SqlConnection objConn = dbaStore.OrderSqlConnection(strSite);
32         SqlDataAdapter objAdapter = new SqlDataAdapter(strSql, objConn);
33         try
34         {
35             DataSet ds = new DataSet();
36             objAdapter.Fill(ds, "dt");
37             return ds.Tables["dt"];
38         }
39         catch (SqlException e)
40         {
41             //这里面写能够写ErrorLog
42         }
43     }
44 
45 
46 }
DBA

上面2个类就能够完成我所想的功能,由于用的是Static写的,因此能够直接用,因而就有了下面的Sql语句:"select * from Table where Id='XXX'",若是我想得到A公司的数据,就以下调用:DBA.GetDataTable("A",SqlStatemet);(SqlStatement即为前面黄色背景的Sql语句)设计

拿着改写好的SqlHelper,向我师傅炫耀去了,师傅看过以后邹着眉头说,你这样写当然是有好处的,可是你将原本对数据库没有任何意义的公司别传入SqlHelper,增长了耦合度,虽然解决了如今的问题,可是对之后的拓展应该是很差的。(其实静态类就这点很差,实在没法完美支持SqlHelper,若是哪位师兄有好的方法,请必定不要吝啬指导我)

好吧,第一次出师就不利,简单和师傅还有咱们经理讨论了下将来SqlHelper的架构方向,一致决定在整合的页面中再也不使用静态类去完成Sql语句,转而用工厂模式来写咱们的SqlHelper.

在《Head First》中,工厂模式用的是Pizza的例子来诠释的,有一个Pizza来决定如何作Pizza,有一个PizzaStore来决定如何作哪一个地区的Pizza.

因而我把SqlHelper的变化部分抽象出来,写一个抽象类SqlStatement,里面有GetConnection(得到不一样公司的链接字符串)Result(得到不一样的返回值,例如DataTa或者首行首列等)两种抽象方法,由SqlStatement来决定如何去执行一个Sql,另外写一个DBAStore来决定得到哪一个公司的链接字符串。

代码以下:

相似于Pizza的抽象超类,实现如何执行Sql。DBAStore,功能和类名同样,抽象用来实现,决定得到哪一个公司的链接字符串。

 1     public abstract class SqlStatement
 2     {
 3         public abstract SqlConnection GetSqlConnection();
 4 
 5         public abstract object Result(string strSql);
 6         //{
 7         //    //SqlConnection sqlConnection = GetSqlConnection(strSite);
 8         //    //return SqlCommand(strSql,get);
 9         //}
10     }
SqlStatement
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Data.SqlClient;
 4 using System.Linq;
 5 using System.Text;
 6 using System.Threading.Tasks;
 7 
 8 namespace DBHelp
 9 {
10     public abstract class DBAStore
11     {
12         public SqlConnection OrderDBA(string strSite)
13         {
14             SqlConnection objConn;
15             objConn = CreateDBA(strSite);
16             return objConn;
17         }
18         public abstract SqlConnection CreateDBA(string strSite);
19     }
20     public class OA : DBAStore
21     {
22         private string _aConnection= "A公司链接字符串";
23         private string _bConnection = "B公司链接字符串";
24         private string _cConnection = "C公司链接字符串";
25 
26 
27 
28         public string CConnection
29         {
30             get { return _cConnection; }
31             set { _cConnection = value; }
32         }
33 
34         public string BConnection
35         {
36             get { return _bConnection; }
37             set { _bConnection = value; }
38         }
39 
40 
41         public string AConnection
42         {
43             get { return _aConnection; }
44             set { _aConnection = value; }
45         }
46 
47         public override SqlConnection CreateDBA(string strSite)
48         {
49             switch (strSite)
50             {
51                 case "A":
52                     return new SqlConnection(_aConnection);
53                 case "B":
54                     return new SqlConnection(_bConnection);
55                 case "C":
56                     return new SqlConnection(_cConnection);
57                 default:
58                     return null;
59             }
60         }
61     }
62 }
DBAStore

GetDataTable类,继承于SqlStatement,返回一个DataTable类型的dt

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Data;
 4 using System.Data.SqlClient;
 5 using System.Linq;
 6 using System.Text;
 7 using System.Threading.Tasks;
 8 
 9 namespace DBHelp
10 {
11     public class GetDataTable:SqlStatement
12     {
13         private string _strSite;
14 
15         public GetDataTable(string strSite)
16         {
17             _strSite = strSite;
18         }
19 
20         public override SqlConnection GetSqlConnection()
21         {
22             DBAStore dbaStore = new OA();
23             SqlConnection sqlConnection = dbaStore.OrderDBA(_strSite);
24             return sqlConnection;
25         }
26 
27         public override object Result(string strSql)
28         {
29             SqlConnection sqlConnection = GetSqlConnection();
30             SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(strSql, sqlConnection);
31             sqlConnection.Open();
32             try
33             {
34                 DataSet ds = new DataSet();
35                 sqlDataAdapter.Fill(ds, "dt");
36                 return ds.Tables["dt"];
37             }
38             catch
39             {
40                 return null;
41             }
42             finally
43             {
44                 sqlConnection.Close();
45             }
46         }
47     }
48 }
GetDataTable

经过以上三个类,咱们就能够经过New实例的方式来执行Sql,返回须要的数值。

SqlStatement GetDataTable = new GetDataTable("A");//将DB环境切换到A公司,就像在SQL SERVER Management Studio中使用:"USE A"同样。
GetDataTable.Result("select Site from Table where Id in ('XXX','OOO')");//在A公司环境下执行前面黄色背景的Sql语句。

若是您须要返回一个Bool值去判断是否执行插入或者删除语句,那么就新建一个ExecSql,继承于SqlStatement,更改相应参数就能够得到是否执行成功。

由于代码比较容易写,我就再也不提供相应的类了,您能够本身试试,真的很是简单。

 

可是,这时候问题又出来了,每次我使用不一样方法执行Sql,或返回Bool值,或返回一个DataTable值,每次都得New一次,实在很是繁琐了,能不能像之前那样,直接用静态方法,实现相似DBA("A").GetDataTable("Sql语句")或者DBA("B").ExecSql("Sql语句")呢,亲爱的小伙伴,我也在朝这个方向努力,但愿能和你们一块儿探讨如何写更简单的SqlHelper。

 

文章写到最后,我来解释下,为何我要用"类工厂模式"来形容个写的这个SqlHelper呢,聪明的小伙伴,您有没有发现,我在写DBAStore类的时候,在建立一个链接字符串的时候,用了一个Switch来返回不一样公司的链接字符串,这和《Head First》中建立不一样的确Pizza店返回的是Pizza类型的值,而个人DBAStore中没有更过分设计的返回一个SqlStatement类型。因此这点和工厂模式有点差别,为了记念第一次理解工厂模式,就让我用这个"类工厂模式"给本身庆贺吧。

 

写在最后:

由于时间比较晚了,也准备将博文发给同事,让他们帮忙点赞,UML图,暂时就不提供了,后续会提供。

可能您会问,为何不提供一个完整的SqlHelper方法给你们使用?个人解释是,我其实也没有彻底作到我梦想的方式。同时天天等QQ邮箱的时候,能看到有人给我上一篇文章评论的话语,感受倍受鼓舞,若是长时间不更新博文,他们觉得我失踪了,或者觉得我放弃了程序员这个行业,为了他们,我选择将我这个半成品公布出来,让你们使用。

关于代码可否使用:这个您能够放心,我是通过调试的,而且用在咱们公司的正式环境的,是可使用的,只是为了保密和安全性考虑,我截取的时候,可能会有偏差,若是您Copy了代码,可是没法使用,能够联系我索取完整代码。

关于程序员这条路:以前阅读过李开复的自传《让世界因你而不一样》,真的被谷歌、微软等IT巨头的工做环境还有他们所写的酷炫的代码所吸引。回到现实,咱们毕业于最低流大学,大学的时候压根不会去敲代码。即便院长但愿咱们能在4年中敲出20000行代码,实际上咱们压根连200行都没敲出来。毕业后,匆匆忙忙找个培训公司培训,而后去工做,拖控件,重复性工做,长时间加班,一切的实现压碎了咱们的理想。但我想对您和我本身说,人应该有梦想,应该让世界由于咱们的存在而有一点的的确确的不一样。但愿您和我在看到这句话的时候,能摈弃之前的借口,多学习学习,成长为一名合格的程序员,而不是码农、码畜。

 

话有点多,有点啰嗦,并且语言不清晰,逻辑混乱,请您见谅。

相关文章
相关标签/搜索