Удалите зависимость от контейнера МОК

После чтения все больше о контейнерах МОК, я читал это сообщение о не наличии IoC.Resolve () и т.д. в Вашем коде.

Мне действительно любопытно знать затем, как я могу удалить зависимость от контейнера?

Я захочу написать код как следующее:

public void Action()
{
    using(IDataContext dc = IoC.Resolve())
    {
        IUserRepository repo = IoC.Resolve();
        // Do stuff with repo...
    }
}

Но как я могу избавиться от вызовов IoC.Resolve? Возможно, мне нужно лучшее понимание DI...

Заранее спасибо.

17
задан Community 23 May 2017 в 11:51
поделиться

5 ответов

Вообще говоря, большинство зависимостей можно внедрить в ваш класс во время его создания. Однако в этом конкретном случае вам понадобится компонент, который должен создаваться по запросу во время использования. В таких случаях очень сложно полностью удалить зависимость от контейнера IoC. Мой подход всегда заключался в создании фабрики, которая вводится в класс во время создания, что, в свою очередь, инкапсулирует все прямое использование IoC. Это позволяет имитировать ваши фабрики для тестирования, а не сам контейнер IoC ... что, как правило, намного проще:

// In Presentation.csproj
class PresentationController
{
    public PresentationController(IDataContextFactory dataContextFactory, IRepositoryFactory repositoryFactory)
    {
        #region .NET 4 Contract
        Contract.Requires(dataContextFactory != null);
        Contract.Requires(repositoryFactory != null);
        #endregion

        _dataContextFactory = dataContextFactory;
        _repositoryFactory = repositoryFactory;
    }

    private readonly IDataContextFactory _dataContextFactory;
    private readonly IRepositoryFactory _repositoryFactory;

    public void Action()
    {
        using (IDataContext dc = _dataContextFactory.CreateInstance())
        {
            var repo = _repositoryFactory.CreateUserRepository();
            // do stuff with repo...
        }
    }
}

// In Factories.API.csproj
interface IDataContextFactory
{
    IDataContext CreateInstance();
}

interface IRepositoryFactory
{
    IUserRepository CreateUserRepository();
    IAddressRepository CreateAddressRepository();
    // etc.
}

// In Factories.Impl.csproj
class DataContextFactory: IDataContextFactory
{
    public IDataContext CreateInstance()
    {
        var context = IoC.Resolve<IDataContext>();
        // Do any common setup or initialization that may be required on 'context'
        return context;
    }
}

class RepositoryFactory: IRepositoryFactory
{
    public IUserRepository CreateUserRepository()
    {
        var repo = IoC.Resolve<IUserRepository>();
        // Do any common setup or initialization that may be required on 'repo'
        return repo;
    }

    public IAddressRepository CreateAddressRepository()
    {
        var repo = IoC.Resolve<IAddressRepository>();
        // Do any common setup or initialization that may be required on 'repo'
        return repo;
    }

    // etc.
}

Преимущество этого подхода в том, что, хотя вы не можете полностью устранить саму зависимость IoC, вы можете инкапсулируйте его в один вид объекта (фабрику), отделяя основную часть вашего кода от контейнера IoC. Это улучшает гибкость вашего кода в свете, скажем, переключения с одного контейнера IoC на другой (например, из Виндзора в Ninject).

Следует отметить, что интересным следствием этого является то, что ваши фабрики обычно внедряются в свои иждивенцы той же структурой IoC, которую они используют. Если вы, например, используете Castle Windsor, вы должны создать конфигурацию, которая сообщает контейнеру IoC о необходимости внедрения двух фабрик в ваш бизнес-компонент при его создании. Сам бизнес-компонент также может иметь фабрику ... или он может быть просто внедрен той же структурой IoC в компонент более высокого уровня и т. Д. И т. Д. Ad inf.

17
ответ дан 30 November 2019 в 13:20
поделиться

Некоторое время назад я работал над проектом, который не касался контейнера IoC. Они справились с неопределенностью, запретив специфические особенности своего контейнера, не относящиеся к IoC, а также заключив Resolve в собственный класс. Это тоже то, что я видел несколько раз в сообщениях в блогах ... удалите последнюю зависимость, зависимость от контейнера внедрения зависимостей.

Это работоспособный метод, но в какой-то момент вам придется выбрать инструменты, которые вы используете, и быть готовым согласиться с тем, что вы заплатите за переход на альтернативные инструменты. Для меня контейнеры IoC относятся к категории вещей, которые вы, вероятно, должны принять всем сердцем, поэтому я сомневаюсь в этом уровне факторинга. Если вы хотите разобраться в этом подробнее, я предлагаю следующую ссылку:

http://blog.objectmentor.com/articles/2010/01/17/dependency-injection-inversion

2
ответ дан 30 November 2019 в 13:20
поделиться
2
ответ дан 30 November 2019 в 13:20
поделиться

Одной из альтернатив является переписывание метода приема делегатов Func. Это удаляет зависимость из метода и позволяет протестировать ее с помощью макета:

public void Action(Func<IDataContext> getDataContext, Func<IUserRepository> getUserRepository)
{
    using(IDataContext dc = getDataContext())
    {
        IUserRepository repo = getUserRepository();
        // Do stuff with repo...
    }
}
2
ответ дан 30 November 2019 в 13:20
поделиться

Иметь второй зависимый инжектор для впрыска первого, а первый - второй.

1
ответ дан 30 November 2019 в 13:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: