2013-08-27 5 views
0

Я написал DLL для доступа к базам данных. Therefor У меня есть интерфейс под названием 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. Теперь, если другой databaseprovider следует добавить, мне придется сделать следующие шаги:

  • Создать класс (например, MySqlDbInterop) для конкретной реализации
  • Продолжим перечисление (например, MYSQL)
  • Продлить завод чтобы позволить пользователю получить новую реализацию

Есть ли способ, чтобы мне не нужно было расширять перечисление и фабрику при добавлении новой реализации?

+1

Кажется, вы пытаетесь изобрести колесо. Вместо этого используйте Entity Framework. –

+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, который использует метод Injection Injection (Constructor или Setter Injection), чтобы создать конкретный класс для вас. Эти контейнеры IoC внутри могут снова использовать Reflection, как указано в первом пункте.
+0

Я сделал это со статическим конструктором на заводе. в этом конструкторе i итерации по всем классам и поиск интерфейса. интерфейс определяет ReadOnlyProperty, чтобы получить DtType. Эти значения я пишу в статическом словаре. Теперь я могу попросить Factory получить интерфейс-объект для предоставления 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

Этот подход следует Принципу открытого закрывания.

Для упрощения кода вы можете сделать фактических поставщиков услуг для сотрудников. Это означает, что рабочий интерфейс должен наследовать от 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(); 
    } 

Это приходит с ценой нарушения единого принципа ответственности.