首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

實戰分層架構(七・外傳):以 Strategy 模式重構 Access+SQL 資料存取層,消除冗餘與資源洩漏

     編輯:關於.NET

背景與痛點:初版實作的三大缺失

在前一篇〈基於 .NET 平台的分層架構實戰(七)——資料存取層第一種實現:Access+SQL〉發布後,社群反饋熱烈(特別感謝「金色海洋」jyk 的建設性意見)。經歸納,初版程式碼存在三大問題:

  1. Connection 物件未顯式關閉(雖執行期無功能性影響,但屬資源管理缺失)。
  2. DataReader 物件未關閉,易造成連線洩漏。
  3. 相似程式碼大量重複,嚴重違反 DRY 原則。

針對前兩點,DataReader 關閉可在 finally 區塊處理;Connection 若在 DataReader 讀取期間關閉會導致讀取失敗,故暫保留由連線池管理。核心挑戰在於如何優雅地消除冗餘程式碼。

重構策略:三類操作抽象 + Strategy 模式解耦映射邏輯

操作分類與公共流程提煉

分析 DAL 操作,歸納為三類:

  1. 非查詢操作:Insert/Update/Delete,無回傳值。
  2. 單一實體查詢:回傳單一實體物件 (T)。
  3. 實體集合查詢:回傳實體清單 IList<T>。

將三類操作的共同流程(開啟連線、建立命令、綁定參數、執行、資源釋放)抽離至 AccessDALHelper 三個泛型靜態方法,具體的「DataReader 轉實體」邏輯因實體型別不同而異,引入 Strategy 模式 解耦。

策略介面定義

public interface IDataReaderToEntityStrategy<T>
{
    T DataReaderToEntity(OleDbDataReader dataReader);
}

具體策略實作:Singleton 確保全域唯一

以 AdminInfo 為例,實作策略並採用 Singleton 模式:

public class AdminDataReaderToEntityStrategy : IDataReaderToEntityStrategy<AdminInfo>
{
    private static AdminDataReaderToEntityStrategy singleInstance = null;
    private AdminDataReaderToEntityStrategy() { }
    
    public static AdminDataReaderToEntityStrategy GetInstance()
    {
        if (singleInstance == null) singleInstance = new AdminDataReaderToEntityStrategy();
        return singleInstance;
    }
    
    public AdminInfo DataReaderToEntity(OleDbDataReader reader)
    {
        return new AdminInfo {
            ID = (int)reader["ID"],
            Name = (string)reader["Name"],
            Password = (string)reader["Password"]
        };
    }
}

重構後的 AccessDALHelper:三大核心方法

public sealed class AccessDALHelper
{
    // 1. 非查詢操作
    public static void ExecuteSQLNonQuery(string sql, OleDbParameter[] parameters) { ... }
    
    // 2. 回傳 DataReader (供內部使用)
    public static OleDbDataReader ExecuteSQLDataReader(string sql, OleDbParameter[] parameters) { ... }
    
    // 3. 封裝非查詢邏輯
    public static bool OperateNonData(string sql, OleDbParameter[] parameters)
    {
        try { ExecuteSQLNonQuery(sql, parameters); return true; }
        catch { return false; }
    }
    
    // 4. 單一實體查詢
    public static T OperateEntity<T>(string sql, OleDbParameter[] parameters, IDataReaderToEntityStrategy<T> strategy)
    {
        OleDbDataReader reader = ExecuteSQLDataReader(sql, parameters);
        try {
            if (!reader.HasRows) throw new Exception();
            reader.Read();
            return strategy.DataReaderToEntity(reader);
        }
        catch { return default(T); }
        finally { reader.Close(); } // 關鍵:確保 DataReader 釋放
    }
    
    // 5. 實體集合查詢
    public static IList<T> OperateEntityCollection<T>(string sql, OleDbParameter[] parameters, IDataReaderToEntityStrategy<T> strategy)
    {
        OleDbDataReader reader = ExecuteSQLDataReader(sql, parameters);
        try {
            if (!reader.HasRows) throw new Exception();
            var list = new List<T>();
            while (reader.Read()) list.Add(strategy.DataReaderToEntity(reader));
            return list;
        }
        catch { return default(IList<T>); }
        finally { reader.Close(); }
    }
}

極簡的具體 DAL 實作:AdminDAL

引入策略後,AdminDAL 方法縮減為單行委派呼叫:

public class AdminDAL : IAdminDAL
{
    public bool Insert(AdminInfo admin) 
        => AccessDALHelper.OperateNonData("INSERT INTO [TAdmin]([Name],[Password]) VALUES(@name,@password)", 
            new[] { new OleDbParameter("name", admin.Name), new OleDbParameter("password", admin.Password) });
    
    public AdminInfo GetByID(int id) 
        => AccessDALHelper.OperateEntity<AdminInfo>("SELECT * FROM [TAdmin] WHERE [ID]=@id", 
            new[] { new OleDbParameter("id", id) }, AdminDataReaderToEntityStrategy.GetInstance());
    
    public IList<AdminInfo> GetAll() 
        => AccessDALHelper.OperateEntityCollection<AdminInfo>("SELECT * FROM [TAdmin]", null, AdminDataReaderToEntityStrategy.GetInstance());
    // Delete, Update, GetByNameAndPassword, GetByName 同理...
}

設計亮點總結

  • 資源安全:finally 區塊強制關閉 DataReader,杜絕連線洩漏。
  • 零冗餘:連線、命令、參數、讀取、釋放等樣板程式碼集中於 Helper,具體 DAL 僅含 SQL 與參數定義。
  • 開放封閉:新增實體類別只需新增對應 Strategy 類別,無需修改 AccessDALHelper。
  • 型別安全:泛型約束確保編譯期型別檢查,避免執行期轉型錯誤。
  • Singleton 策略:無狀態轉換邏輯共享單一實例,減少物件建立開銷。

此重構展示了如何在輕量級專案中套用經典設計模式,以最小代價達到專業級的程式碼品質。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved