2013-08-27 28 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(); 
    } 

这种带有违反了单一职责原则的成本。