Тестирование контейнера IoC за синглтоном - делать это неправильно?

Как правило, мне нравится, когда приложение полностью игнорирует контейнер IoC. Однако я столкнулся с проблемами, когда мне нужно было получить к нему доступ. Чтобы отвлечься от боли, я использую базовый Синглтон. Прежде чем бежать за холмами или вытащить дробовик, позвольте мне решить мое решение. В принципе, одиночный сингл IoC абсолютно ничего не делает, он просто делегирует внутренний интерфейс, который должен быть передан. Я нашел, что это делает работу с Singleton менее болезненной.

Ниже приведена оболочка IoC:

public static class IoC
    {
        private static IDependencyResolver inner;

        public static void InitWith(IDependencyResolver container)
        {
            inner = container;
        }

        /// <exception cref="InvalidOperationException">Container has not been initialized.   Please supply an instance if IWindsorContainer.</exception>
        public static T Resolve<T>()
        {
            if ( inner == null)
                throw new InvalidOperationException("Container has not been initialized.  Please supply an instance if IWindsorContainer.");

            return inner.Resolve<T>();
        }

        public static T[] ResolveAll<T>()
        {
            return inner.ResolveAll<T>();
        }
    }

IDependencyResolver:

public interface IDependencyResolver
    {
        T Resolve<T>();
        T[] ResolveAll<T>();
    }

У меня был большой успех с тех пор, когда я использовал его (возможно, раз в несколько проектов, я действительно предпочитаю не использовать это вообще), поскольку я могу впрыснуть все, что захочу: Castle, Stub, подделки и т.д.

Это скользкая дорога? Могу ли я столкнуться с потенциальными проблемами в будущем?

Ответ 1

Я видел, что даже Айенде реализует этот образец в коде Rhino Commons, но я бы посоветовал не использовать его там, где это возможно. Там причина, по которой замок Виндзор не имеет этого кода по умолчанию. StructureMap делает, но Джереми Миллер отошел от него. В идеале вы должны рассматривать контейнер как можно больше подозрений, чем любая глобальная переменная.

Однако, как альтернатива, вы всегда можете настроить свой контейнер для разрешения IDependencyResolver в качестве ссылки на ваш контейнер. Это может показаться сумасшедшим, но это значительно более гибким. Просто запомните эмпирическое правило, что объект должен вызывать "новый" или выполнять обработку, но не оба. Для "call new" замените "разрешить ссылку".

Ответ 2

Это не совсем один класс. Это статический класс со статическими членами. И да, это кажется хорошим подходом.

Я думаю, что у JP Boodhoo даже есть имя для этого шаблона. Шаблон статического шлюза.

Ответ 3

Просто заметьте: Microsoft Patterns and Practices создали общий локатор сервисов (http://www.codeplex.com/CommonServiceLocator), что большинство основных контейнеров IoC будут будет осуществляться в ближайшем будущем. Вы можете начать использовать его вместо вашего IDependencyResolver.

Кстати: это общий способ решить вашу проблему, и он работает достаточно хорошо.

Ответ 4

Все зависит от использования. Использование такого контейнера называется шаблоном Locator службы. Бывают случаи, когда это не подходит и случаи, когда они применяются.

Если вы указали "шаблон локатора сервисов Google", вы увидите много сообщений в блогах, в которых говорится, что это анти-шаблон, которого нет. Шаблон просто был использован (/злоупотребление).

Для типичной линейки бизнес-приложений вы не должны использовать SL при скрытии зависимостей. У вас также возникла еще одна проблема: вы не можете управлять состоянием/временем жизни, если используете корневой контейнер (вместо одного из его сроков жизни).

Локатор сервисов подходит для инфраструктуры. Например, ASP.NET MVC использует Service Locator для разрешения всех зависимостей для каждого контроллера.