Кажется, на SO есть клеймо в отношении использования синглетонов. Я никогда не покупал это лично, но ради открытости я пытаюсь дать концепции IoC альтернативу, потому что мне откровенно надоела моя повседневная работа, и я хотел бы попробовать что-то другое. Простите, если моя интерпретация понятий IoC неверна или ошибочна.
Вот ситуация: я создаю простой веб-сервер на основе HttpListener
в службе Windows, который использует модель подключаемого модуля для определения способа обработки запроса на основе запрошенного 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<string, Type>
, единственная цель которого - отслеживать, о каких модулях мы знаем. Этот словарь обычно встречается в моем разнообразии синглтонов, которые берут на себя персону синглтона в стиле ACE (наследие моих дней в C ++, где я узнал о синглетонах).
Теперь я пытаюсь реализовать нечто подобное, используя (мое понимание) общие концепции IoC. По сути, у меня есть коллекция AppService
, где IAppService
определяется как:
public interface IAppService : IDisposable
{
void Initialize();
}
А мой плагин AppService
будет выглядеть примерно так:
[AppService("Plugins")]
internal class PluginAppService : IAppService, IDictionary<string, Type>
{
/* 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<string, IAppService>
{
/* 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, которая упростила бы все это, или есть ли польза для всего этого дополнительного кода? В моем мире синглтоны - это простые существа, которые позволяют коду всей программы получать доступ к необходимой (относительно статичной) информации (в данном случае типов).
Чтобы задать вопросы более четко:
- Является ли это действительной реализацией Factory Singleton, переведенной в понятия IoC / DI?
- Если это так, где окупаемость / выгода для дополнительного кода и навязывание, казалось бы, более неуклюжего API?