#c# #architecture #ioc-container
#c# #архитектура #ioc-контейнер
Вопрос:
Мой вопрос касается архитектуры программного обеспечения в целом.
Давайте рассмотрим пример:
У нас есть приложение-служба Windows.
Program.cs создает и запускает экземпляр MainService
класса.
MainService
наследуется от, ServiceBase
следовательно, реализует OnStart(string[] args)
метод.
Обычно, когда я разрабатываю свое приложение, я бы сделал что-то подобное в OnStart
методе:
MainSingletonObject.Initialize();
Инициализация будет считывать данные конфигурации из app.config и создавать экземпляры требуемых классов, открывать хосты WCF (если таковые имеются) и т.д.
Является ли это хорошей практикой для запуска приложения-службы? Каким был бы ваш личный архитектурный совет по улучшению дизайна? Куда поместить контейнер IoC и зачем он мне нужен, если я прекрасно выполняю внедрение зависимостей вручную.
Комментарии:
1. Я вижу две проблемы с этим: 1) вы используете одноэлементный антипаттерн ( jalf.dk/blog/2010/03 /… ), и 2) это не служит никакой цели. Архитектура программного обеспечения заключается не в наложении шаблонов друг на друга, а в структурировании программы таким образом, чтобы ее было легко разрабатывать, понимать и поддерживать. Всему, что не способствует одному из них, не место в вашей архитектуре. Итак, что вы получаете, создавая такой одноэлемент вместо обычного класса или даже функции?
2. Я получаю чистый код. Вместо того, чтобы вызывать var myMainClass = new MainClass(); и myMainClass. Start (); У меня есть только одна строка кода в методе service OnStart. Каким преимуществом было бы просто создать объект и запустить метод?
3. Но вы можете быть правы, я теряю и способность передавать параметры конструктору. Я мог бы просто прочитать все зависимости из app.config в методе OnStart и, если возникнет проблема, указать, что запуск службы завершился неудачно.
4. Преимуществом было бы упрощение кода. У вас все еще может быть только одна строка кода в
OnStart
, если вы считаете, что это важно. (Просто вызовите его, например,RunMain()
, илиnew MyApp().Run()
(и оба они могут принимать параметры так же хорошо, как ваш одноэлементInitialize()
). И затем вы можете удалить весь подверженный ошибкам, непроверяемый и хрупкий одноэлементный код, который больше не служит никакой цели.
Ответ №1:
Я бы использовал IoC на этапе начальной загрузки сервиса здесь:
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new ServiceClass()
};
ServiceBase.Run(ServicesToRun);
Вместо того, чтобы иметь new ServiceClass
, я бы разрешил класс обслуживания через IoC. Таким образом, вы избегаете зависимости IoC в реализации сервиса. Если вам нужно создать с помощью инъекции совершенно новый объект изнутри вашей реализации, рассмотрите возможность предоставления сервиса, ITypeFactory
зарегистрированного в IoC, который изолирует ваш код от конкретного контейнера, который вы будете использовать. В общем, вы можете оценить хороший дизайн в IoC, если вы также изолируете контейнер.
Ответ №2:
При инициализации Singleton не должен зависеть от других. Он инициализируется, как только он используется.
Вот как я бы это сделал:
public class MySingleton
{
private static readonly MySingleton _instance = new MySingleton();
private MySingleton()
{
// ... read config
}
public static MySingleton Instance
{
get { return _instance; }
}
}
Здесь static readonly
удостоверяется, что это отложенная загрузка.