Архитектурно заменить одноэлементный основной объект контейнером IoC

#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 удостоверяется, что это отложенная загрузка.