"類工廠模式"改寫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行都沒敲出來。畢業後,匆匆忙忙找個培訓公司培訓,而後去工做,拖控件,重複性工做,長時間加班,一切的實現壓碎了咱們的理想。但我想對您和我本身說,人應該有夢想,應該讓世界由於咱們的存在而有一點的的確確的不一樣。但願您和我在看到這句話的時候,能擯棄之前的藉口,多學習學習,成長爲一名合格的程序員,而不是碼農、碼畜。

 

話有點多,有點囉嗦,並且語言不清晰,邏輯混亂,請您見諒。

相關文章
相關標籤/搜索