IoC benefits over my Factory Singleton

There seems to be stigma regarding the use of singletones. I never personally bought into it, but for the sake of an open mind, I try to give the IoC concept a try as an alternative, because I am frankly bored of my daily work and I want to try something else. Forgive me if my interpretation of IoC concepts is wrong or wrong.

Here's the situation: I'm HttpListener based web server in a Windows service that uses a plug-in model to determine how to process a request based on the requested URL (like everyone else who asks about the HttpListener ). My approach to opening plugins is to request a customized directory for assemblies decorated with HttpModuleAssemblyAttribute . These assemblies can contain 0 or more IHttpModule children, which are additionally decorated with the HttpModuleAttribute used to indicate the module name, version, human-readable description, and other information. Something like:

 [HttpModule(/*Some property values that matter */)] public class SimpleHttpModule : IHttpModule { public void Execute(HttpListenerContext context) { /* Do Something Special */ } } 

When an HttpModule detected HttpModule I usually add it to the Dictionary<string, Type> object, whose sole purpose is to keep track of which modules we know. This dictionary, as a rule, lives in my diversity of Singleton, which takes on the character ACE Singleton Style (a legacy from my C ++ days, where I learned about singletones).

Now what I'm trying to implement is something similar, using (my understanding) the general concepts of IoC. Basically, I have a collection of AppService , where IAppService is defined as:

 public interface IAppService : IDisposable { void Initialize(); } 

And my AppService plugin will look something like this:

 [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 } 

Then, during the OnStart service, I create an instance of AppServices , which is locally known, but passed to the constructor of all installed plugins:

 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); } } 

Our implementation of one single method becomes an abstract implementation + constructor for a child:

 [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 */ } } 

And any access to commonly used application services becomes:

 var plugType = appServices["Plugins"][plugName]; 

but not:

 var plugType = PluginManager.Instance[plugName]; 

I skipped some basic IoC concepts here that would simplify this all or is this really an advantage for all this extra code? In my world, Singletons are simple creatures that allow code through the entire program to access the necessary (relatively static) information (in this case, they are types).

To ask questions in more detail:

  • Is this a valid version of Factory Singleton translated into IoC / DI concepts?
  • If so, where is the payback / benefit for additional code and the imposition of a seemingly more awkward API?
+7
source share
3 answers

While I'm still not sure that IoC / DI is better in this situation, I definitely saw a benefit as the project expanded. For things like logging and configuration, this is definitely the right approach.

I look forward to experimenting with him in future projects.

+1
source

IoC is a general term. Dependency injection is the preferred term these days.

Dependence Injection does shine in several circumstances. First, it defines a more testable architecture than solutions that have hard-coded dependency instances. Singletones are complex unit test, because they are static, and static data cannot be "offloaded".

Secondly, Injection Dependency not only creates the type you want, but also all dependent types. Thus, if class A needs class B, and class B needs classes C and D, then a good DI structure will automatically create all the dependencies and control their life time (for example, forcing them to live throughout the life cycle of a single web request).

DI containers can be like universal factories that can instantiate any object (provided that it is properly configured and meets the requirements of the DI infrastructure). Therefore, you do not need to write a custom factory.

As with any general solution, it is designed to provide 90% of the use cases that they need. Undoubtedly, you could create a data structure with an individual linked list manually every time you need a collection, but 90 =% of the time when the general one will work fine. The same goes for DI and Custom Factory.

+2
source

IoC gets more interesting when you get around writing unit tests. Sorry that the answer to the question asked more questions, but ... What would the unit tests look like for both of your implementations? Can you unit test classes that used PluginManager without looking at assemblies from disk?

EDIT

Just because you can achieve the same functionality with singletones doesn't mean it's easy to maintain. Using IoC (at least this style with constructors), you explicitly specify the dependencies that the object has. Using singleton information is hidden inside the class. It also makes it difficult to replace these dependencies with alternative implementations.

Thus, using singleton PluginManager it would be difficult to test your HTTP server using plugins with layouts rather than looking for them from anywhere on the disk. With the IoC version, you can pass an alternate version of IAppService , which simply looks at the plugins from the pre-populated Dictionary .

+1
source

All Articles