Использование Funcs вместо экземпляров в рамках - PullRequest
4 голосов
/ 02 марта 2011

При просмотре исходного кода пары проектов я обнаружил шаблон, который не совсем понимаю.Например, в FubuMVC и Common Service Locator a Func используется при изменении статического поставщика.Может кто-нибудь объяснить, какая выгода от использования:

private static Func<IServiceLocator> currentProvider;
public static IServiceLocator Current
{
   get { return currentProvider(); }
}

public static void SetLocatorProvider(Func<IServiceLocator> newProvider)
{
   currentProvider = newProvider;
}

вместо:

private static IServiceLocator current;
public static IServiceLocator Current
{
   get { return current; }
}

public static void SetLocator(IServiceLocator newInstance)
{
   current = newInstance;
}

Ответы [ 4 ]

9 голосов
/ 02 марта 2011

Основным преимуществом первой модели перед второй является то, что называется «отложенной инициализацией». Во втором примере, как только вызывается SetLocator, у вас должен быть экземпляр IServiceLocator, загруженный в память и готовый к работе. Если такие экземпляры дороги в создании и / или создании вместе с кучей других объектов одновременно (как при запуске приложения), будет хорошей идеей попытаться отложить фактическое создание объекта, чтобы уменьшить заметные задержки для пользователя. Кроме того, если зависимость не может использоваться зависимым классом (скажем, она нужна только для определенных операций, а класс может выполнять другие действия, не требующие зависимости), было бы бесполезно создавать ее экземпляр.

Решение состоит в том, чтобы предоставить «фабричный метод» вместо фактического экземпляра. Когда экземпляр действительно необходим, вызывается фабричный метод, и экземпляр создается в последний момент, прежде чем его использовать. Это сокращает время загрузки внешнего интерфейса и позволяет избежать создания ненужных зависимостей.

2 голосов
/ 30 мая 2011

Хороший ответ от @KeithS.Еще одна вещь, на которую следует обратить внимание, это то, что происходит под прикрытием инициализации определенных экземпляров.Сохранение ссылки на намеренно изменчивые объекты может быть непростым делом.

Например, FubuMVC раскручивает вложенный контейнер StructureMap для каждого HTTP-запроса, который охватывает все расположение службы для этого конкретного запроса.Если у вас есть классы, работающие в этом конвейере, которые были созданы, вы захотите использовать контекстную инъекцию, предоставленную вам через экземпляр THer IServiceLocator.

1 голос
/ 02 марта 2011

Функция позволяет несколько вещей

  1. Создание локатора может быть отложено до тех пор, пока оно не понадобится. Поэтому ленивый.
  2. Объект провайдера не содержит никакого состояния. Он не обязан выключать локатор, что-либо с ним делает, кроме как возвращать текущий локатор при необходимости.
  3. Когда локатор реконфигурируется во время выполнения или он решает, что нужен другой экземпляр, он может управлять временем жизни локатора, пока вызывающий код не хранит ссылку на локатор.
  4. Поскольку локатор возвращается методом, он обладает большей гибкостью, например, создать локальный локатор потока, чтобы он мог создавать множество объектов в каждом потоке без необходимости координировать создание объекта в одном глобальном объекте, который может стать узким местом, когда задействовано много потоков.

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

С уважением, Алоис Краус

1 голос
/ 02 марта 2011

Существует гораздо больше гибкости для разработчика newProvider. Они могут выполнять отложенную загрузку, асинхронную загрузку (а затем, если она не загружается к моменту вызова функции, она может иметь код для ожидания), они могут разрешить ее изменение в зависимости от параметров времени выполнения и т. Д.

...