2013-08-27 55 views
0

我寫了一個訪問數據庫的DLL。爲此我有一個名爲IDbInterop接口看起來像:工廠創建數據庫交互

public interface IDbInterop 
    { 
     void ExecuteCommandNonQuery(string commandText, params IDbParameter[] commandParameter); 
     object ExecuteCommandScalar(string commandText, params IDbParameter[] commandParameter); 
     DataSet ExecuteCommandDataSet(string commandText, params IDbParameter[] commandParameter); 
    } 

爲了得到這個接口的實例爲spezific databaseprovider,我介紹了一個工廠,需要一個枚舉作爲參數來決定哪些具體的實現應該被創建:

public static class DbInteropFactory 
{ 
    public static IDbInterop BuildDbInterop(DbType dbType, string connectionString) 
    { 
     switch (dbType) 
     { 
      case DbType.MSSQL: 
       return new MSSQLDbInterop(connectionString); 
      default: 
       throw new ArgumentOutOfRangeException("dbType"); 
     } 
    } 
} 

public enum DbType 
{ 
    MSSQL, 
} 

我只對目前爲止的MSSQL數據庫實現了一個concret實現。現在,如果另一databaseprovider應加入我必須做以下步驟:

  • 的具體實施
  • 創建一個類(如MySqlDbInterop)延長枚舉(如MYSQL)
  • 延長工廠允許用戶獲得新的實現

有沒有辦法,我不必擴展枚舉和工廠,如果添加新的實現?

+1

對我來說,你試圖重新發明輪子。改爲使用實體框架。 –

+3

使用類似nInject的依賴注入?這是解決這類問題的通用解決方案。 –

+0

什麼是您的解決方案給你的.NET DbProviderFactory類不? http://msdn.microsoft.com/en-us/library/system.data.common.dbproviderfactory.aspx – Joe

回答

1

是的,至少有三種方式我知道。

  1. 您可以使用Reflection來實例化具體類,但您可能需要處理任何性能問題。
  2. 您可以讓具體類向工廠註冊,但您需要確保在任何客戶端請求其實例之前進行註冊。
  3. 您可以使用任何可用的IoC containers,它使用依賴注入(Constructor或Setter Injection)原理爲您實例化具體類。這些內部IoC容器可能會再次使用Reflection,如第一點所述。
+0

我已經在工廠使用了靜態構造函數。在這個構造函數中,我遍歷所有類並搜索接口。該接口定義了一個ReadOnlyProperty來獲得它的DbType。這個值我寫在一個靜態的字典。現在我可以讓工廠獲取給DbType的接口對象 – Tomtom

0

是的,有一種方法。使用工廠工人。工作人員創建一個實例並具有匹配參數的知識。

public interface IFactoryWorker 
{ 
    IDbInterop CreateInterop(string connectionString); 
    bool AcceptParameters(string ProviderName); 
} 

一個例子工人將

public class SqlServerFactoryWorker : IFactoryWorker 
{ 
    public IDbInterop CreateInterop(string connectionString) 
    { 
     return new MSSQLDbInterop(connectionString);  
    } 

    public bool AcceptParameters(string providerName) 
    { 
     return providerName == "System.Data.SqlClient"; 
    } 
} 

那麼你的工廠變得

public static class DbInteropFactory 
{ 
    private static List<IFactoryWorker> _workers; 

    static DbInteropFactory() 
    { 
     _workers = new List<IFactoryWorker>(); 
     _workers.Add(new SqlServerFactoryWorker()); 
    } 

    public static void AddWorker(IFactoryWorker worker) 
    { 
     _workers.Add(worker); 
    } 

    public static IDbInterop BuildDbInterop( 
    string ProviderName, string connectionString) 
    { 
    foreach (var worker in _workers) 
    { 
     if (worker.AcceptParameters(ProviderName)) 
      return worker.CreateInterop(connectionString); 

     // or return null 
     throw new ArgumentException(); 
    } 
    } 

這種方法具有以下優點:

  • 有字符串作爲提供商類型意味着你不必擴展任何enums
  • 讓工人在工廠外工作意味着您永遠不必改變工廠本身
  • 創建新提供者意味着您創建一個新工人並在工廠註冊,這可以在工廠之外完成與AddWorker方法

此方法遵循開放 - 閉合原則。

爲了簡化代碼,您可以讓工作人員實際使用interop提供程序。這意味着工作接口應該從IDbInterop繼承並實現所有的邏輯。在這種方法中,工廠試圖找到「工人提供商」(foreach (var worker in _workers),並發現時,則返回:

public interface IFactoryWorker : IDbInterop 
{ 
    IDbInterop CreateInterop(string connectionString); 
    bool AcceptParameters(string ProviderName); 
} 

    ... 
    foreach (var worker in _workers) 
    { 
     if (worker.AcceptParameters(ProviderName)) 
      return worker; 

     // or return null 
     throw new ArgumentException(); 
    } 

這種帶有違反了單一職責原則的成本。