Контейнер для инъекций зависимостей - PullRequest
0 голосов
/ 25 января 2011

У меня есть библиотека уровня доступа к данным, которую я хотел бы сделать «переносимой». Мне нравится его переносимость, потому что я хочу работать с хранилищем файлов SQL Azure и Azure (например, отчетами data + pdf), а также с хранилищем Sql Server 2008R2 и файловой системы на конкретном сервере.

Исходя из спецификаций, система должна начать работу с более поздней реализацией (хранилище файловой системы sql +), а при достижении определенного порога масштабируемости мы планируем перейти на Azure.

Класс доступа к данным, который я использую, реализует интерфейс IDataProvider (который я создал) и определяет методы, которые должна иметь любая конкретная реализация доступа к данным. Использование уровня доступа к данным осуществляется путем передачи интерфейса IDataProvider и вызова на нем методов, например:

public Interface IDataProvider
{
    public bool DoSomething();
}

public class AzureDataProvider : IDataProvider
{
    private string ConnectionString;

    public AzureDataProvider(string connectionString)
    {
        this.ConnectionString = connectionString;
    }

    public AzureDataProvider():this(
        ConfigurationManager.ConnectionString["conn"].ConnectionString)
    {
    }

    public bool DoSomething()
    {
        return false;
    }
}

Так что теперь проблема в том, что класс потребителя, который будет вызывать методы в интерфейсе IDataProvider, должен сделать следующее:

public class DataAccessConsumer
{
    public void SomeOperation()
    {
        AzureDataProvider azureProvider = new AzureDataProvider();
        IDataProvider dataProvider = (IDataProvider)azureProvider;

        bool result = dataProvider.DoSomething();
    }
}

Таким образом, проблема с приведенным выше кодом заключается в том, что клиент все еще должен знать конкретный класс AzureDataProvider. Я хочу иметь метод предоставления клиенту только интерфейса IDataProvider без передачи строки подключения для каждого метода интерфейса или поиска строки подключения в каждом методе через ConfigurationManager.

Это возможно? Подойдет ли Абстрактная Фабрика или какой-нибудь шаблон Контейнера Инъекции зависимостей? Если это так, я был бы признателен за примеры кода или ссылки на примеры кода.

Ответы [ 2 ]

1 голос
/ 27 января 2011

Ну, я выкатил свой собственный DI.Если цель состоит в том, чтобы добиться мобильности, то, я думаю, я пришел к полуоприемлемому решению.Недостатки в том, что вы не можете по-настоящему достичь полного DI, однако в контексте моего приложения он достаточно хорош.

Интерфейс подключения:

public interface IConnection
{
    public string ConnectionString;
}

Реализация конкретного соединения

public class Connection: IConnection
{
    public string ConnectionString{ get; set; }

    public Connection(string connectionString)
    {
        this.ConnectionString = connectionString;
    }

    public Connection():this(ConfigurtionManager.ConnectionStrings["connection"].ConnectionString)
    {
        //Broke DI in the interest of usability.
    }
}

Интерфейс уровня доступа к данным

public interface IDataProvider
{
    IConnection Connection;

    public void Foo();
}

Реализация уровня доступа к конкретным данным

public class AzureProvider : IDataProvider
{
    IConnection Connection { get; set; }

    public AzureProvider(IConnection connection)
    {
        this.Connection = connection;
    }

    public void Foo()
    {

    }
}

DI Conainer / Factory (Singleton или статический класс)

public static class ProviderFactory
{
    public static IDataProvider GetProvider()  //I'd pass parameters if I had more than 1.
    {
        Connection connection = new Connection(); //this is why I broke DI.
        IConnection iConnection = (IConnection)connection;

        AzureProvider azureProvider = new AzureProvider(iConnection);
        IDataProvider iDataProvider = (IDataProvider)azureProvider;

        return iDataProvider;
    }
}

Потребитель уровня доступа к данным (в данном примере это страница):

public class SomePage : Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        IDataProvider provider = ProviderFactory.GetProvider();
        provider.Foo();
    }
}

Как видите, странице не нужно знать какие-либо подробности реализации уровня доступа к данным.Пока ProviderFactory может выплевывать IDataProvider, страница довольна.Поэтому, если мы решим сменить провайдера, скажем SqlStorageProvider, до тех пор, пока он реализует интерфейс IDataProvider, код страницы не нужно будет менять.Это позволяет разделить проблемы с точки зрения архитектуры программного обеспечения.

1 голос
/ 25 января 2011

Во-первых, AzureDataProvider зависит от ConfigurationManager. Это должно быть введено вместо.

Во-вторых, этот DataProvider должен быть внедрен в DataAccessConsumer.

Это означает, что реалистичное приложение будет иметь хорошее внедрение зависимостей повсеместно, без зависимости от контейнера, однако затем вам потребуется «проводка» - соединение всех зависимостей вместе. Это боль - используйте DependencyInjectionContainer только в главной точке входа, чтобы помочь разрешить эту разводку. (Это позволяет вам использовать более удобный декларативный подход, а не императивный, поскольку вы можете задать контейнеру «Получить мне DataAccessConsumer», и среда внедрения зависимостей определит для вас зависимости.

Моя любимая среда внедрения зависимостей для C # - NInject2.

...