Похоже, на SO есть клеймо в отношении использования синглтонов. я лично никогда не покупался на это, но ради непредубежденности я пытаюсь попробовать концепции IoC в качестве альтернативы, потому что мне откровенно скучно моя повседневная работа и я хотел бы попробовать что-то другое. Простите меня, если моя интерпретация Концепции IoC неверны или ошибочны.
Вот ситуация: я создаю простой веб-сервер на основе HttpListener
в службе Windows, который использует модель подключаемых модулей для определения того, как запрос sh может обрабатываться на основе запрошенного URL (как и все, кто спрашивает о HttpListener
). Мой подход к обнаружению подключаемых модулей состоит в том, чтобы запросить настроенный каталог для сборок, украшенных HttpModuleAssemblyAttribute
.Эти сборки могут содержать 0 или более IHttpModule
дочерних, которые, кроме того, украшены HttpModuleAttribute
, используемым для указания имени модуля, версии, удобочитаемого описания и другой другой информации. Что-то вроде:
[HttpModule(/*Some property values that matter */)]
public class SimpleHttpModule : IHttpModule
{
public void Execute(HttpListenerContext context)
{
/* Do Something Special */
}
}
Когда обнаруживается HttpModule
, я обычно добавляю его к объекту Dictionary
, единственная цель которого - отслеживать, о каких модулях мы знаем . Этот словарь, как правило, находится в моей разновидности синглтона, который принимает образ синглтона в стиле ACE (наследие от моих дней C ++, когда я узнал о синглтонах).
Сейчас я пытаюсь реализовать нечто подобное, используя (мое понимание) общие концепции IoC.В основном у меня есть коллекция AppService
, где IAppService
определяется как:
public interface IAppService : IDisposable
{
void Initialize();
}
И мой плагин AppService
будет выглядеть примерно так:
[AppService("Plugins")]
internal class PluginAppService : IAppService, IDictionary
{
/* Common IDictionary Implementation consisting of something like: */
internal Type Item(string modName)
{
Type modType;
if (!this.TryGetValue(modName, out modType)
return null;
return modType;
}
internal void Initialize()
{
// Find internal and external plug-ins and add them to myself
}
// IDisposable clean up method that attempts to dispose all known plug-ins
}
Тогда во время обслуживания OnStart
Я создаю экземпляр AppServices
, который известен локально, но передается конструктору всех созданных экземпляров подключаемых модулей:
public class AppServices : IDisposable, IDictionary
{
/* Simple implementation of IDictionary */
public void Initialization()
{
// Find internal IAppService implementations, instantiate them (passing this as a constructor parameter), initialize them and add them to this.
// Somewhere in there would be something like
Add(appSvcName, appSvc);
}
}
Наша единственная реализация метода становится абстрактной реализацией + конструктор дочернего элемента:
[HttpModule(/*Some property values that matter */)]
public abstract class HttpModule : IHttpModule
{
protected AppServices appServices = null;
public HttpModule(AppServices services)
{
appServices = services;
}
public abstract void Execute(HttpListenerContext context);
}
[HttpModule(/*Some property values that matter */)]
public class SimpleHttpModule : HttpModule
{
public SimpleHttpModule(AppServices services) : base(services) { }
public override void Execute(HttpListenerContext context)
{
/* Do Something Special */
}
}
И любой доступ к часто используемым службам приложений становится:
var plugType = appServices["Plugins"][plugName];
, а не:
var plugType = PluginManager.Instance[plugName];
Мне не хватает здесь какой-то базовой концепции IoC, которая упростила бы все это, или действительно есть преимущества для всех этот дополнительный код? В моем мире синглтоны - это простые существа, которые позволяют коду программы получать доступ к необходимой (относительно статической) информации (в данном случае - к типам).
Чтобы задать вопросы более подробно: