Как мне обрабатывать статические классы при использовании IOC - PullRequest
4 голосов
/ 27 июня 2010

Я только что начал миграцию своего веб-приложения, чтобы полностью использовать Windsor 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
       }
}

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

Ответы [ 3 ]

4 голосов
/ 27 июня 2010

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

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

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

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

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

3 голосов
/ 27 июня 2010

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

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

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

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

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

container.AddComponentLifeStyle<SiteInfo>(LifestyleType.Singleton)

или,

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

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

По этой причине альтернативным образом жизни является веб-запрос - другими словами, контейнер будет создавать новый экземпляр вашего класса SiteInfo один раз за веб-запрос.Стиль жизни для каждого веб-запроса обсуждается в другом вопросе .

0 голосов
/ 27 июня 2010

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

...