2010-06-27 3 views
4

Я только что начал переносить свое веб-приложение, чтобы полностью использовать Windsor IOC. Вот небольшая проблема, с которой я сталкиваюсь;Как обрабатывать статические классы при использовании IOC

У меня есть пара статических классов, которые я использовал для хранения некоторых глобальных значений на уровне приложения

EG (Упрощенная версия класса):

public static class SiteInfo 
{ 
     public static Language Language = (Language)byte.Parse(SiteInfo.Val("language")); 
     public static string Code = Site.Code; 
     public static string Name = Site.Name; 

     public static SiteCachedData CachedData { get; set; } 
     public static Site Site { get; set; } 

     public static void Init() 
     { 
      //Get site info from DB here 
      //I need to inject _SiteRepository here but I can't 
      //since I don't have access to the constructor 
     } 
} 

Я новичок в МОК, и я понимаю, статические классы рекомендуется предотвращать. Какова хорошая практика для решения этой ситуации? Я думаю о преобразовании этого в одноэлементный, но я не уверен, что это мой лучший выбор.

ответ

0

Вы можете зарегистрировать один instanec класса в своем контейнере, поэтому он ведет себя как одноэлементный. Контейнер дает вам один и тот же экземпляр каждый раз.

3

Это одна из причин, почему мне нравится избегать статических классов - их трудно вводить или инвертировать. Они обычно должны знать интимные подробности нескольких классов низкого уровня. Поскольку они являются статическими классами, вы можете оставить их, потому что они уже доступны для всех других классов и не требуют инъекции.

Один трюк, который я сделал, - создать второй класс, который делегирует в статический класс. Затем вы можете поместить интерфейс в новый класс и легче войти в структуру IoC.

public static class StaticClass 
{ 
    public static object Method() 
} 

public class NonstaticClass : INewInterface 
{ 
    public object Method() 
    { 
     return StaticClass.Method(); 
    } 
} 

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

3

В контексте контейнера IoC несколько двусмысленно сказать «преобразовать его в одноэлементный». Если вы имеете в виду singleton design pattern, вы, вероятно, не должны этого делать, поскольку в мире IoC есть лучшие альтернативы.

Контейнеры IoC выполняют две основные роли: разрешать зависимости между компонентами и управлять временем жизни компонентов. Контейнер управляет временем жизни своих компонентов, решая, когда создавать и уничтожать экземпляры компонентов.

Например, когда вы вызываете container.Resolve<SiteInfo>(), контейнер должен решить, следует ли повторно использовать существующий экземпляр SiteInfo или создать новый. Как контейнер принимает решение? Ну, когда вы регистрируете SiteInfo с контейнером, вы можете указать контейнеру, как вы хотите, чтобы он себя вел. Если вы зарегистрируете его как Singleton, контейнер будет создавать экземпляр SiteInfo только при первом вызове container.Resolve<SiteInfo>(); при последующих вызовах он повторно использует существующий экземпляр SiteInfo.

Преимущество этой техники над шаблоном одноэлементности - гибкость. Если вы используете шаблон дизайна, ваш SiteInfo-класс навсегда останется синглом (если вы не будете рефактором). Используя контейнер для управления временем жизни, вы можете изменить свое мнение позже и просто изменить код регистрации контейнера. Потребителям компонента не нужно (и не должно) заботиться о том, предоставляет ли контейнер им новый экземпляр или повторно использует существующий - они просто вызывают container.Resolve().

Я не знаком с Виндзор (я использую Autofac), но, похоже, у вас есть два способа регистрации компоненты как синглтон (я уверен, что кто-то меня поправит, если это не так):

container.AddComponentLifeStyle<SiteInfo>(LifestyleType.Singleton) 

или

container.Register(Component.For<SiteInfo>() 
        .LifeStyle.Singleton); 

Однако слово предупреждения. В вашем примере ваш класс SiteInfo имеет зависимость от класса _SiteRepository. Поэтому вам также необходимо зарегистрировать экземпляр _SiteRepository в качестве одноэлементного в контейнере, чтобы он был доступен, когда контейнер разрешает SiteInfo. Этот экземпляр _SiteRepository останется в памяти на время жизни контейнера, т. Е. На время жизни веб-приложения, потому что это одноэлемент. Поэтому, если хранилище поддерживает соединение с БД, значит, это соединение останется открытым для одного и того же срока службы.

Для такого рода альтернативного образа жизни используется веб-запрос - другими словами, контейнер создаст новый экземпляр класса SiteInfo один раз для каждого веб-запроса. Образ жизни для каждого веб-сайта обсуждается в another question.

Смежные вопросы