工厂创建数据库交互

时间:2013-08-27 15:28:48

标签: c# database

我已经编写了一个用于访问数据库的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);
    }

为了获得一个特定数据库提供者的接口实例,我引入了一个工厂,它以枚举作为参数来决定应该创建哪个具体实现:

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实现。现在,如果要添加另一个数据库提供者,我将不得不执行以下步骤:

  • 为具体实现创建一个类(例如MySqlDbInterop)
  • 扩展枚举(例如MYSQL)
  • 扩展工厂以允许用户获得新的实现

有没有办法,如果添加新的实现,我不必扩展枚举和工厂?

2 个答案:

答案 0 :(得分:1)

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

  1. 您可以使用Reflection来实例化具体类,但您可能必须处理任何性能问题。
  2. 您可以让具体类在工厂注册,但您需要确保在任何客户请求其实例之前进行注册。
  3. 您可以使用任何可用的IoC containers使用依赖注入(构造函数或Setter注入)原则来为您实例化具体类。内部的这些IoC容器可以再次使用Reflection,如第一点所述。

答案 1 :(得分: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();
     }
  }

这种方法有以下好处:

  • 将字符串作为提供者类型意味着您不必扩展任何枚举
  • 在工厂外工作意味着您永远不必更换工厂本身
  • 创建新的提供者意味着您创建一个新的工作者并在工厂注册它,这可以通过AddWorker方法在工厂外完成

这种方法遵循开放 - 封闭原则。

为了简化代码,您可以使工作人员成为实际的互操作提供者。这意味着worker接口应该继承自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();
     }

这是违反单一责任原则的成本。