2008-11-10 3 views
10

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

Ниже 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>(); 
    } 

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

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

ответ

4

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

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

3

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

Я думаю, что у JP Boodhoo даже есть имя для этого шаблона. The Static Gateway pattern.

2

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

BTW: Это распространенный способ решить вашу проблему, и это работает очень хорошо.

1

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

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

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

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