淺談.NET策略模式
策略模式在我們日常開發中經常被用到,這篇文章不是策略模式的深入討論和學術研究,只是讓初學者能有個基本的了解。
什么叫策略:1. 可以實現目標的方案集合;2. 根據形勢發展而制定的行動方針和斗爭方法;3. 有斗爭藝術,能注意方式方法。
什么叫模式:模式(Pattern)其實就是解決某一類問題的方法論。把解決某類問題的方法總結歸納到理論高度,那就是模式。模式是一種指導,在一個良好的指導下,有助于你完成任務,有助于你作出一個優良的設計方案,達到事半功倍的效果。而且會得到解決問題的***辦法。
什么叫策略模式:策略模式定義了一系列的算法,并將每一個算法封裝起來,而且使它們還可以相互替換。策略模式讓算法獨立于使用它的客戶而獨立變化。
從上面的官方解釋來看,我們已經有了一個基本的雛形。其實設計模式就是前輩們所總結出來的,用來解決某類問題的方法論;這些方法論是經過身經百戰的專家們提煉出來的,比較規范的、比較科學的模型。
其實設計模式對初學者來說可能有點頭疼,比較抽象。大概就是因為初學者對一些概念不能深度的理解,一些理論知識還沒能夠融會貫通,不過不要緊經過一段時間的實踐鍛煉就能理解了;下面我們循環漸進的來講解什么叫策略模式。我們拿真實項目中遇到的問題來講解吧,這樣能更好的吸引注意力。
情景引入:
您是否遇到過這樣一個頭疼的問題,在我們開發信息系統的時候,經常需要切換不同的數據庫。但是由于我們前期開發項目的時候沒有考慮到后期的變更,所以這個時候問題就來了。如果需要更換數據庫,將大動干戈把代碼翻個底朝天。將諸如一些Sql、Oledb、Oracle之類的對象進行全局替換。這樣的設計永遠都無法滿足日后的數據庫變更需求。所以在前期設計的時候,我們就需要考慮到系統后期可能存在哪些可能變化的地方,在系統的架構上就需要變通設計(比如:依賴接口而不是具體的對象,通過依賴注入等方式進行策略的變更;)。其實這個時候我們很需要一種模式能解決此類問題,恰好前輩們為我們準備好了(策略模式)。[設計模式的設計原則:盡可能的考慮系統后期的變化;]
1.沒有分析之前的系統結構:
情景分析:
我們暫且不談設計模式,我們試著自己分析一下問題。我們需要一種機制,能在需要的時候自動變更后臺數據源的連接對象;我們來收集問題,既然要自動變更后臺數據源連接對象,那么我們在編碼的過程中就不能直接使用一些諸如SqlConnection、SqlCommand等對象,必須進行提取形成接口,消除類之間的強耦合。[面向對象編程原則:面向接口編程,而不是面向實現編程;]
2.分析之后的系統結構圖:
情景分析->接口提取:
- /*----------------------------------------------------------------
- * 作者:王清培
- * 時間:2010-10-29
- * ----------------------------------------------------------------*/
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Data;
- using System.Data.SqlClient;
- namespace W.Data
- {
- /// <summary>
- /// 通用數據源類型接口,
- /// 確定每種數據源必須實現基本的對IDbConnection,IDbCommand,IDbTransaction 三者的包裝;
- /// </summary>
- public interface IDataSourceType
- {
- #region 屬性
- /// <summary>
- /// 獲取或設置數據源連接字符串。
- /// </summary>
- string ConnectionString { get; set; }
- #endregion
- /// <summary>
- /// 開始數據庫事務。
- /// </summary>
- void BeginTransaction();
- /// <summary>
- /// 提交事務處理。
- /// </summary>
- void Commit();
- /// <summary>
- /// 從掛起狀態回滾事務。
- /// </summary>
- void Rollback();
- /// <summary>
- /// 執行查詢,并返回查詢所返回的結果集DataSet。
- /// </summary>
- /// <param name="cmdText">要執行的命令文本</param>
- /// <returns>DataSet</returns>
- DataSet ExecuteDataSet(string commandtext);
- /// <summary>
- /// 執行查詢,并返回查詢所返回的結果集DataSet。
- /// </summary>
- /// <param name="commandtype"> 指定如何解釋命令字符串。</param>
- /// <param name="commandtext">命令文本</param>
- /// <param name="parameter">IDbDataParameter參數列表</param>
- /// <returns>DataSet</returns>
- DataSet ExecuteDataSet(CommandType commandtype, string commandtext, params IDataParameter[] parameter);
- /// <summary>
- /// 對連接執行 Transact-SQL 語句并返回受影響的行數。
- /// </summary>
- /// <param name="cmdText">命令文本</param>
- /// <returns>受影響的行數</returns>
- int ExecuteNonQuery(string cmdText);
- /// <summary>
- /// 對連接執行 Transact-SQL 語句并返回受影響的行數。
- /// </summary>
- /// <param name="commandtype">指定如何解析命令字符串</param>
- /// <param name="commandtext">命令文本</param>
- /// <param name="parameter">IDbDataParameter參數列表</param>
- /// <returns>受影響的行數</returns>
- int ExecuteNonQuery(CommandType commandtype, string commandtext, params IDataParameter[] parameter);
- /// <summary>
- /// 對連接執行 Transact-SQL 語句并返回受影響的行數。
- /// </summary>
- /// <param name="conn">IDbConnection對象</param>
- /// <param name="cmdType">指定如何解析命令字符串</param>
- /// <param name="cmdText">命令文本</param>
- /// <param name="commandParameters">IDbDataParameter參數列表</param>
- /// <returns>受影響的行數</returns>
- int ExecuteNonQuery(IDbConnection conn, CommandType cmdType, string cmdText, params IDataParameter[] parameter);
- /// <summary>
- ///對連接執行 Transact-SQL 語句并返回受影響的行數。已事務的方式執行
- /// </summary>
- /// <param name="trans">IDbTransaction對象。</param>
- /// <param name="cmdType">指定如何解析命令字符串。</param>
- /// <param name="cmdText">命令文本。</param>
- /// <param name="commandParameters">IDbDataParameter參數列表。</param>
- /// <returns>受影響的行數。</returns>
- int ExecuteNonQuery(IDbTransaction trans, CommandType cmdType, string cmdText, params IDataParameter[] parameter);
- /// <summary>
- /// 將 System.Data.SqlClient.SqlCommand.CommandText 發送到
- /// System.Data.SqlClient.SqlCommand.Connection 并生成一個 System.Data.SqlClient.SqlDataReader。
- /// </summary>
- /// <param name="cmdText">執行的命令文本</param>
- /// <returns>IDataReader對象</returns>
- IDataReader ExecuteReader(string cmdText);
- /// <summary>
- /// 將 System.Data.SqlClient.SqlCommand.CommandText 發送到
- /// System.Data.SqlClient.SqlCommand.Connection 并生成一個 System.Data.SqlClient.SqlDataReader。
- /// </summary>
- /// <param name="cmdType">指定如何解析命令字符串</param>
- /// <param name="cmdText">命令文本</param>
- /// <param name="commandParameters">IDataParameter參數列表</param>
- /// <returns>IDataReader對象</returns>
- IDataReader ExecuteReader(CommandType cmdType, string cmdText, params IDataParameter[] parameter);
- /// <summary>
- /// 執行查詢,并返回查詢所返回的結果集中***行的***列。忽略其他列或行。
- /// </summary>
- /// <param name="cmdText">命令文本</param>
- /// <returns>結果集中***行的***列;如果結果集為空,則為空引用(在 Visual Basic 中為 Nothing)</returns>
- object ExecuteScalar(string cmdText);
- /// <summary>
- /// 執行查詢,并返回查詢所返回的結果集中***行的***列。忽略其他列或行。
- /// </summary>
- /// <param name="cmdType">指定如何解析命令字符串</param>
- /// <param name="cmdText">命令文本</param>
- /// <param name="commandParameters">IDataParameter參數列表</param>
- /// <returns>結果集中***行的***列;如果結果集為空,則為空引用(在 Visual Basic 中為 Nothing)。</returns>
- object ExecuteScalar(CommandType cmdType, string cmdText, params IDataParameter[] parameter);
- /// <summary>
- /// 執行查詢,并返回查詢所返回的結果集DataTable。
- /// </summary>
- /// <param name="cmdText">命令文本</param>
- /// <returns>DataTable</returns>
- DataTable ExecuteTable(string cmdText);
- /// <summary>
- ///執行查詢,并返回查詢所返回的結果集DataTable。
- /// </summary>
- /// <param name="cmdType">指定如何解析命令字符串</param>
- /// <param name="cmdText">命令文本</param>
- /// <param name="commandParameters">IDataParameter參數列表</param>
- /// <returns>DataTable</returns>
- DataTable ExecuteTable(CommandType cmdType, string cmdText, params IDataParameter[] parameter);
- /// <summary>
- /// 關閉數據庫連接。
- /// </summary>
- void Close();
- /// <summary>
- /// 執行與釋放或重置非托管資源相關的應用程序定義的任務。
- /// </summary>
- void Dispose();
- }
- }
情景分析->OLEDB數據源實現:
- /*----------------------------------------------------------------
- * 作者:王清培
- * 時間:2010-10-29
- * ----------------------------------------------------------------*/
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Configuration;
- using System.Data.OleDb;
- using System.Data;
- namespace W.Data
- {
- /// <summary>
- /// OLEDB數據源
- /// </summary>
- public sealed class OledbSource : IDataSourceType, IDisposable
- {
- #region 字段
- /// <summary>
- /// 是否已開始數據庫事務處理
- /// </summary>
- private bool _begin = false;
- /// <summary>
- /// IDbConnection對象(包裝的SqlConnection對象)
- /// </summary>
- private OleDbConnection _connection;
- /// <summary>
- /// IDbTransaction對象(包裝的SqlTransaction對象)
- /// </summary>
- private OleDbTransaction _transaction;
- /// <summary>
- /// 靜態全局(SQLServerSource數據源)實例連接字符串對象;
- /// </summary>
- private static string _globalconnectionstring = string.Empty;
- #endregion
- #region 屬性
- /// <summary>
- /// 獲取,靜態全局SQLServerSource數據源實例連接字符串對象;
- /// </summary>
- public static string GlobalConnectionString
- {
- get { return _globalconnectionstring; }
- }
- /// <summary>
- /// 獲取或設置本次執行的數據源的連接字符串
- /// </summary>
- public string ConnectionString
- {
- get { return _connection.ConnectionString; }
- set { _connection.ConnectionString = value; }
- }
- /// <summary>
- /// 獲取包裝的SqlTransaction對象
- /// </summary>
- public OleDbTransaction SqlTransaction
- {
- get { return _transaction; }
- }
- #endregion
- #region 構造函數
- /// <summary>
- /// 靜態構造函數。
- /// </summary>
- static OledbSource()
- {
- //設置全局(SQLServerSource實例)對象的默認連接字符串
- _globalconnectionstring = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
- }
- /// <summary>
- ///默認實例構造函數
- /// </summary>
- public OledbSource()
- {
- _connection = new OleDbConnection(_globalconnectionstring);
- }
- /// <summary>
- /// 重載構造函數,使用指定連接字符串來初始化 CommandLib.Data.SQLServerSource 類的新實例。默認所有的SQLServerSource實例均使用
- /// 配置文件中的SQLServerConnectionString類型的連接字符串。
- /// </summary>
- /// <param name="connectionstring">連接字符串</param>
- public OledbSource(string connectionstring)
- {
- _connection = new OleDbConnection(connectionstring);
- }
- #endregion
- #region 實例方法
- /// <summary>
- /// 開始數據庫事務。
- /// </summary>
- public void BeginTransaction()
- {
- _begin = true;
- _connection.Open();
- _transaction = _connection.BeginTransaction();//新建數據源的事務對象
- }
- /// <summary>
- /// 提交事務處理。
- /// </summary>
- public void Commit()
- {
- _begin = false;
- _transaction.Commit();
- _transaction = null;//事務執行完畢全部清除(事務不是很常用不需要一直保留)
- _connection.Close();
- }
- /// <summary>
- /// 從掛起狀態回滾事務。
- /// </summary>
- public void Rollback()
- {
- _begin = false;
- _transaction.Rollback();
- _transaction = null;//事務執行完畢全部清除(事務不是很常用不需要一直保留)
- _connection.Close();
- }
- /// <summary>
- /// 執行查詢,并返回查詢所返回的結果集DataSet。
- /// </summary>
- /// <param name="commandtext">命令文本</param>
- /// <returns>DataSet</returns>
- public DataSet ExecuteDataSet(string commandtext)
- {
- return ExecuteDataSet(CommandType.Text, commandtext, null);
- }
- /// <summary>
- /// 執行查詢,并返回查詢所返回的結果集DataSet。
- /// </summary>
- /// <param name="commandtype">指定如何解釋命令字符串</param>
- /// <param name="commandtext">命令文本</param>
- /// <param name="parameter">IDbDataParameter參數列表</param>
- /// <returns>DataSet</returns>
- public DataSet ExecuteDataSet(CommandType commandtype, string commandtext, params IDataParameter[] parameter)
- {
- if (_connection.State == ConnectionState.Closed)
- _connection.Open();
- OleDbCommand commmand = InitSqlCommand(commandtype, commandtext, parameter);
- OleDbDataAdapter adapter = new OleDbDataAdapter(commmand);
- DataSet ds = new DataSet();
- adapter.Fill(ds);
- return ds;
- }
- /// <summary>
- /// 對連接執行 Transact-SQL 語句并返回受影響的行數。
- /// </summary>
- /// <param name="cmdText">命令文本</param>
- /// <returns>受影響的行數</returns>
- public int ExecuteNonQuery(string cmdText)
- {
- return ExecuteNonQuery(CommandType.Text, cmdText, null);
- }
- /// <summary>
- /// 對連接執行 Transact-SQL 語句并返回受影響的行數。
- /// </summary>
- /// <param name="commandtype">IDbConnection對象</param>
- /// <param name="commandtext">指定如何解析命令字符串</param>
- /// <param name="parameter">命令文本</param>
- /// <returns>受影響的行數</returns>
- public int ExecuteNonQuery(CommandType commandtype, string commandtext, params IDataParameter[] parameter)
- {
- if (_connection.State == ConnectionState.Closed)
- _connection.Open();
- OleDbCommand command = InitSqlCommand(commandtype, commandtext, parameter);
- return command.ExecuteNonQuery();
- }
- /// <summary>
- /// 重載ExecuteNonQuery方法。
- /// </summary>
- /// <param name="conn">IDbConnection對象</param>
- /// <param name="cmdType">指定如何解析命令字符串</param>
- /// <param name="cmdText">命令文本</param>
- /// <param name="commandParameters">IDbDataParameter參數列表</param>
- /// <returns>受影響的行數</returns>
- public int ExecuteNonQuery(IDbConnection conn, CommandType cmdType, string cmdText, params IDataParameter[] parameter)
- {
- OleDbCommand command = InitSqlCommand(cmdType, cmdText, parameter);
- command.Connection = (conn as OleDbConnection);
- return command.ExecuteNonQuery();
- }
- /// <summary>
- /// 重載ExecuteNonQuery方法。以事務的方式執行
- /// </summary>
- /// <param name="trans">IDbTransaction對象。</param>
- /// <param name="cmdType">指定如何解析命令字符串。</param>
- /// <param name="cmdText">命令文本。</param>
- /// <param name="commandParameters">IDbDataParameter參數列表。</param>
- /// <returns>受影響的行數。</returns>
- public int ExecuteNonQuery(IDbTransaction trans, CommandType cmdType, string cmdText, params IDataParameter[] parameter)
- {
- OleDbCommand command = InitSqlCommand(cmdType, cmdText, parameter);
- command.Transaction = (trans as OleDbTransaction);
- return command.ExecuteNonQuery();
- }
- /// <summary>
- /// 將 System.Data.SqlClient.SqlCommand.CommandText 發送到
- /// System.Data.SqlClient.SqlCommand.Connection 并生成一個 System.Data.SqlClient.SqlDataReader。
- /// </summary>
- /// <param name="cmdText">執行的命令文本</param>
- /// <returns>IDataReader對象</returns>
- public IDataReader ExecuteReader(string cmdText)
- {
- return ExecuteReader(CommandType.Text, cmdText, null);
- }
- /// <summary>
- /// 將 System.Data.SqlClient.SqlCommand.CommandText 發送到
- /// System.Data.SqlClient.SqlCommand.Connection 并生成一個 System.Data.SqlClient.SqlDataReader。
- /// </summary>
- /// <param name="cmdType">指定如何解析命令字符串</param>
- /// <param name="cmdText">命令文本</param>
- /// <param name="commandParameters">IDataParameter參數列表</param>
- /// <returns>IDataReader對象</returns>
- public IDataReader ExecuteReader(CommandType cmdType, string cmdText, params IDataParameter[] parameter)
- {
- OleDbCommand command = InitSqlCommand(cmdType, cmdText, parameter);
- return command.ExecuteReader();
- }
- /// <summary>
- /// 執行查詢,并返回查詢所返回的結果集中***行的***列。忽略其他列或行。
- /// </summary>
- /// <param name="cmdText">命令文本</param>
- /// <returns>結果集中***行的***列;如果結果集為空,則為空引用(在 Visual Basic 中為 Nothing)</returns>
- public object ExecuteScalar(string cmdText)
- {
- return ExecuteScalar(CommandType.Text, cmdText, null);
- }
- /// <summary>
- /// 執行查詢,并返回查詢所返回的結果集中***行的***列。忽略其他列或行。
- /// </summary>
- /// <param name="cmdType">指定如何解析命令字符串</param>
- /// <param name="cmdText">命令文本</param>
- /// <param name="commandParameters">IDataParameter參數列表</param>
- /// <returns>結果集中***行的***列;如果結果集為空,則為空引用(在 Visual Basic 中為 Nothing)。</returns>
- public object ExecuteScalar(CommandType cmdType, string cmdText, params IDataParameter[] parameter)
- {
- OleDbCommand command = InitSqlCommand(cmdType, cmdText, parameter);
- return command.ExecuteScalar();
- }
- /// <summary>
- /// 執行查詢,并返回查詢所返回的結果集DataTable。
- /// </summary>
- /// <param name="cmdText">命令文本</param>
- /// <returns>DataTable</returns>
- public DataTable ExecuteTable(string cmdText)
- {
- return ExecuteTable(CommandType.Text, cmdText, null);
- }
- /// <summary>
- ///執行查詢,并返回查詢所返回的結果集DataTable。
- /// </summary>
- /// <param name="cmdType">指定如何解析命令字符串</param>
- /// <param name="cmdText">命令文本</param>
- /// <param name="commandParameters">IDataParameter參數列表</param>
- /// <returns>DataTable</returns>
- public DataTable ExecuteTable(CommandType cmdType, string cmdText, params IDataParameter[] parameter)
- {
- OleDbCommand command = InitSqlCommand(cmdType, cmdText, parameter);
- DataTable resulttb = new DataTable();
- OleDbDataAdapter adapter = new OleDbDataAdapter(command);
- adapter.Fill(resulttb);
- return resulttb;
- }
- /// <summary>
- /// 私有方法實現內部類的SqlCommand的初始化
- /// </summary>
- /// <param name="commandtype">IDbConnection對象</param>
- /// <param name="commandtext">指定如何解析命令字符串</param>
- /// <param name="parameter">命令文本</param>
- /// <returns>SqlCommand</returns>
- private OleDbCommand InitSqlCommand(CommandType commandtype, string commandtext, params IDataParameter[] parameter)
- {
- OleDbCommand command = new OleDbCommand(commandtext, _connection);
- command.CommandType = commandtype;
- if (_transaction != null)
- command.Transaction = _transaction;
- if (parameter != null)
- command.Parameters.AddRange(parameter);
- return command;
- }
- /// <summary>
- /// 關閉數據庫連接。
- /// </summary>
- public void Close()
- {
- _connection.Close();
- }
- /// <summary>
- /// 執行與釋放或重置非托管資源相關的應用程序定義的任務。
- /// </summary>
- public void Dispose()
- {
- _connection.Dispose();
- }
- #endregion
- }
- }
這段代碼來源我自己的ORM框架中的。我假設實現一個Oledb數據源。但是怎么將對象送給前臺調用者呢,方法有很多中可以通過工廠、IOC控制器、策略方法都可以,我是用的工廠實現的;這里我就不貼出代碼了,給出調用代碼吧,可以完整的結束了;
情景分析->調用代碼:
- /// <summary>
- /// 根據實體對象和IDataSourceType對象刪除一條記錄,
- /// 該實體必須明確主鍵值才能刪除記錄;如果該實體沒有主鍵可自己編寫SQL代碼刪除;
- /// </summary>
- /// <typeparam name="T">要刪除的表對應的實體對象</typeparam>
- /// <param name="t">Model實體</param>
- /// <param name="idatasource">IDataSourceType數據源類型對象</param>
- /// <returns>刪除是否成功;1成功,0失敗</returns>
- public static int DeleteModelById<T>(T t, IDataSourceType idatasource) where T : new()
- {
- string sqlstring;//保存要執行的T-SQL語句
- List<IDataParameter> paramlist = (List<IDataParameter>)GetDeleteModelParameterT_SQL<T>(t, out sqlstring);//獲取利用Model刪除時的語句和參數列表
- if (idatasource != null)
- return idatasource.ExecuteNonQuery(CommandType.Text, sqlstring, paramlist.ToArray());
- return IDataSourceTypeFactory.Create().ExecuteNonQuery(CommandType.Text, sqlstring, paramlist.ToArray());
- }
總結:調用程序使用接口統一調用數據源不需要關心后臺是什么數據源,工廠通過在策略集合中找到合適的策略給調用著;策略模式大概就講完了,謝謝。
原文鏈接:http://www.cnblogs.com/wangiqngpei557/archive/2011/07/20/2111450.html
【編輯推薦】