Абстрагирование контейнера IoC за синглтоном - это неправильно? - PullRequest
10 голосов
/ 10 ноября 2008

Как правило, мне нравится, когда приложение полностью игнорирует контейнер 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 , подделки и т. д.

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

Ответы [ 4 ]

4 голосов
/ 13 ноября 2008

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

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

3 голосов
/ 10 ноября 2008

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

Я думаю, что у JP Boodhoo даже есть название для этого паттерна. Статический шлюз .

2 голосов
/ 11 ноября 2008

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

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

1 голос
/ 28 июня 2013

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

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

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

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

...